Merge changes I8b15407d,I2667b6f5,I8c83c6b7 into main am: b2bcebca81 am: 3dde652e8e am: a88f5d96a5 am: bfe49379cd
Original change: https://android-review.googlesource.com/c/platform/frameworks/av/+/2620617
Change-Id: Ib706bcb4667511471f09b872c38d7bf1e5e69594
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/media/codec2/hal/common/include/codec2/common/BufferTypes.h b/media/codec2/hal/common/include/codec2/common/BufferTypes.h
new file mode 100644
index 0000000..319ba62
--- /dev/null
+++ b/media/codec2/hal/common/include/codec2/common/BufferTypes.h
@@ -0,0 +1,1928 @@
+/*
+ * 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-types"
+#include <android-base/logging.h>
+
+#include <codec2/hidl/1.0/types.h>
+#include <media/stagefright/foundation/AUtils.h>
+
+#include <C2AllocatorIon.h>
+#include <C2AllocatorGralloc.h>
+#include <C2BlockInternal.h>
+#include <C2Buffer.h>
+#include <C2Component.h>
+#include <C2FenceFactory.h>
+#include <C2Param.h>
+#include <C2ParamInternal.h>
+#include <C2PlatformSupport.h>
+#include <C2Work.h>
+#include <util/C2ParamUtils.h>
+
+#include <algorithm>
+#include <functional>
+#include <iomanip>
+#include <unordered_map>
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace c2 {
+namespace V1_0 {
+namespace utils {
+
+using ::android::hardware::Return;
+using ::android::hardware::media::bufferpool::BufferPoolData;
+using ::android::hardware::media::bufferpool::V2_0::BufferStatusMessage;
+using ::android::hardware::media::bufferpool::V2_0::ResultStatus;
+using ::android::hardware::media::bufferpool::V2_0::implementation::
+ ClientManager;
+using ::android::hardware::media::bufferpool::V2_0::implementation::
+ TransactionId;
+
+const char* asString(Status status, const char* def) {
+ return asString(static_cast<c2_status_t>(status), def);
+}
+
+namespace /* unnamed */ {
+
+template <typename EnumClass>
+typename std::underlying_type<EnumClass>::type underlying_value(
+ EnumClass x) {
+ return static_cast<typename std::underlying_type<EnumClass>::type>(x);
+}
+
+template <typename Common, typename DstVector, typename SrcVector>
+void copyVector(DstVector* d, const SrcVector& s) {
+ static_assert(sizeof(Common) == sizeof(decltype((*d)[0])),
+ "DstVector's component size does not match Common");
+ static_assert(sizeof(Common) == sizeof(decltype(s[0])),
+ "SrcVector's component size does not match Common");
+ d->resize(s.size());
+ std::copy(
+ reinterpret_cast<const Common*>(&s[0]),
+ reinterpret_cast<const Common*>(&s[0] + s.size()),
+ reinterpret_cast<Common*>(&(*d)[0]));
+}
+
+// C2ParamField -> ParamField
+bool objcpy(ParamField *d, const C2ParamField &s) {
+ d->index = static_cast<ParamIndex>(_C2ParamInspector::GetIndex(s));
+ d->fieldId.offset = static_cast<uint32_t>(_C2ParamInspector::GetOffset(s));
+ d->fieldId.size = static_cast<uint32_t>(_C2ParamInspector::GetSize(s));
+ return true;
+}
+
+struct C2ParamFieldBuilder : public C2ParamField {
+ C2ParamFieldBuilder() : C2ParamField(
+ static_cast<C2Param::Index>(static_cast<uint32_t>(0)), 0, 0) {
+ }
+ // ParamField -> C2ParamField
+ C2ParamFieldBuilder(const ParamField& s) : C2ParamField(
+ static_cast<C2Param::Index>(static_cast<uint32_t>(s.index)),
+ static_cast<uint32_t>(s.fieldId.offset),
+ static_cast<uint32_t>(s.fieldId.size)) {
+ }
+};
+
+// C2WorkOrdinalStruct -> WorkOrdinal
+bool objcpy(WorkOrdinal *d, const C2WorkOrdinalStruct &s) {
+ d->frameIndex = static_cast<uint64_t>(s.frameIndex.peeku());
+ d->timestampUs = static_cast<uint64_t>(s.timestamp.peeku());
+ d->customOrdinal = static_cast<uint64_t>(s.customOrdinal.peeku());
+ return true;
+}
+
+// WorkOrdinal -> C2WorkOrdinalStruct
+bool objcpy(C2WorkOrdinalStruct *d, const WorkOrdinal &s) {
+ d->frameIndex = c2_cntr64_t(s.frameIndex);
+ d->timestamp = c2_cntr64_t(s.timestampUs);
+ d->customOrdinal = c2_cntr64_t(s.customOrdinal);
+ return true;
+}
+
+// C2FieldSupportedValues::range's type -> ValueRange
+bool objcpy(
+ ValueRange* d,
+ const decltype(C2FieldSupportedValues::range)& s) {
+ d->min = static_cast<PrimitiveValue>(s.min.u64);
+ d->max = static_cast<PrimitiveValue>(s.max.u64);
+ d->step = static_cast<PrimitiveValue>(s.step.u64);
+ d->num = static_cast<PrimitiveValue>(s.num.u64);
+ d->denom = static_cast<PrimitiveValue>(s.denom.u64);
+ return true;
+}
+
+// C2FieldSupportedValues -> FieldSupportedValues
+bool objcpy(FieldSupportedValues *d, const C2FieldSupportedValues &s) {
+ switch (s.type) {
+ case C2FieldSupportedValues::EMPTY: {
+ d->empty(::android::hidl::safe_union::V1_0::Monostate{});
+ break;
+ }
+ case C2FieldSupportedValues::RANGE: {
+ ValueRange range{};
+ if (!objcpy(&range, s.range)) {
+ LOG(ERROR) << "Invalid C2FieldSupportedValues::range.";
+ d->range(range);
+ return false;
+ }
+ d->range(range);
+ break;
+ }
+ case C2FieldSupportedValues::VALUES: {
+ hidl_vec<PrimitiveValue> values;
+ copyVector<uint64_t>(&values, s.values);
+ d->values(values);
+ break;
+ }
+ case C2FieldSupportedValues::FLAGS: {
+ hidl_vec<PrimitiveValue> flags;
+ copyVector<uint64_t>(&flags, s.values);
+ d->flags(flags);
+ break;
+ }
+ default:
+ LOG(DEBUG) << "Unrecognized C2FieldSupportedValues::type_t "
+ << "with underlying value " << underlying_value(s.type)
+ << ".";
+ return false;
+ }
+ return true;
+}
+
+// ValueRange -> C2FieldSupportedValues::range's type
+bool objcpy(
+ decltype(C2FieldSupportedValues::range)* d,
+ const ValueRange& s) {
+ d->min.u64 = static_cast<uint64_t>(s.min);
+ d->max.u64 = static_cast<uint64_t>(s.max);
+ d->step.u64 = static_cast<uint64_t>(s.step);
+ d->num.u64 = static_cast<uint64_t>(s.num);
+ d->denom.u64 = static_cast<uint64_t>(s.denom);
+ return true;
+}
+
+// FieldSupportedValues -> C2FieldSupportedValues
+bool objcpy(C2FieldSupportedValues *d, const FieldSupportedValues &s) {
+ switch (s.getDiscriminator()) {
+ case FieldSupportedValues::hidl_discriminator::empty: {
+ d->type = C2FieldSupportedValues::EMPTY;
+ break;
+ }
+ case FieldSupportedValues::hidl_discriminator::range: {
+ d->type = C2FieldSupportedValues::RANGE;
+ if (!objcpy(&d->range, s.range())) {
+ LOG(ERROR) << "Invalid FieldSupportedValues::range.";
+ return false;
+ }
+ d->values.resize(0);
+ break;
+ }
+ case FieldSupportedValues::hidl_discriminator::values: {
+ d->type = C2FieldSupportedValues::VALUES;
+ copyVector<uint64_t>(&d->values, s.values());
+ break;
+ }
+ case FieldSupportedValues::hidl_discriminator::flags: {
+ d->type = C2FieldSupportedValues::FLAGS;
+ copyVector<uint64_t>(&d->values, s.flags());
+ break;
+ }
+ default:
+ LOG(WARNING) << "Unrecognized FieldSupportedValues::getDiscriminator()";
+ return false;
+ }
+ return true;
+}
+
+} // unnamed namespace
+
+// C2FieldSupportedValuesQuery -> FieldSupportedValuesQuery
+bool objcpy(
+ FieldSupportedValuesQuery* d,
+ const C2FieldSupportedValuesQuery& s) {
+ if (!objcpy(&d->field, s.field())) {
+ LOG(ERROR) << "Invalid C2FieldSupportedValuesQuery::field.";
+ return false;
+ }
+ switch (s.type()) {
+ case C2FieldSupportedValuesQuery::POSSIBLE:
+ d->type = FieldSupportedValuesQuery::Type::POSSIBLE;
+ break;
+ case C2FieldSupportedValuesQuery::CURRENT:
+ d->type = FieldSupportedValuesQuery::Type::CURRENT;
+ break;
+ default:
+ LOG(DEBUG) << "Unrecognized C2FieldSupportedValuesQuery::type_t "
+ << "with underlying value " << underlying_value(s.type())
+ << ".";
+ d->type = static_cast<FieldSupportedValuesQuery::Type>(s.type());
+ }
+ return true;
+}
+
+// FieldSupportedValuesQuery -> C2FieldSupportedValuesQuery
+bool objcpy(
+ C2FieldSupportedValuesQuery* d,
+ const FieldSupportedValuesQuery& s) {
+ C2FieldSupportedValuesQuery::type_t dType;
+ switch (s.type) {
+ case FieldSupportedValuesQuery::Type::POSSIBLE:
+ dType = C2FieldSupportedValuesQuery::POSSIBLE;
+ break;
+ case FieldSupportedValuesQuery::Type::CURRENT:
+ dType = C2FieldSupportedValuesQuery::CURRENT;
+ break;
+ default:
+ LOG(DEBUG) << "Unrecognized FieldSupportedValuesQuery::Type "
+ << "with underlying value " << underlying_value(s.type)
+ << ".";
+ dType = static_cast<C2FieldSupportedValuesQuery::type_t>(s.type);
+ }
+ *d = C2FieldSupportedValuesQuery(C2ParamFieldBuilder(s.field), dType);
+ return true;
+}
+
+// C2FieldSupportedValuesQuery -> FieldSupportedValuesQueryResult
+bool objcpy(
+ FieldSupportedValuesQueryResult* d,
+ const C2FieldSupportedValuesQuery& s) {
+ d->status = static_cast<Status>(s.status);
+ return objcpy(&d->values, s.values);
+}
+
+// FieldSupportedValuesQuery, FieldSupportedValuesQueryResult ->
+// C2FieldSupportedValuesQuery
+bool objcpy(
+ C2FieldSupportedValuesQuery* d,
+ const FieldSupportedValuesQuery& sq,
+ const FieldSupportedValuesQueryResult& sr) {
+ if (!objcpy(d, sq)) {
+ LOG(ERROR) << "Invalid FieldSupportedValuesQuery.";
+ return false;
+ }
+ d->status = static_cast<c2_status_t>(sr.status);
+ if (!objcpy(&d->values, sr.values)) {
+ LOG(ERROR) << "Invalid FieldSupportedValuesQueryResult::values.";
+ return false;
+ }
+ return true;
+}
+
+// C2Component::Traits -> IComponentStore::ComponentTraits
+bool objcpy(
+ IComponentStore::ComponentTraits *d,
+ const C2Component::Traits &s) {
+ d->name = s.name;
+
+ switch (s.domain) {
+ case C2Component::DOMAIN_VIDEO:
+ d->domain = IComponentStore::ComponentTraits::Domain::VIDEO;
+ break;
+ case C2Component::DOMAIN_AUDIO:
+ d->domain = IComponentStore::ComponentTraits::Domain::AUDIO;
+ break;
+ case C2Component::DOMAIN_IMAGE:
+ d->domain = IComponentStore::ComponentTraits::Domain::IMAGE;
+ break;
+ case C2Component::DOMAIN_OTHER:
+ d->domain = IComponentStore::ComponentTraits::Domain::OTHER;
+ break;
+ default:
+ LOG(DEBUG) << "Unrecognized C2Component::domain_t "
+ << "with underlying value " << underlying_value(s.domain)
+ << ".";
+ d->domain = static_cast<IComponentStore::ComponentTraits::Domain>(
+ s.domain);
+ }
+
+ switch (s.kind) {
+ case C2Component::KIND_DECODER:
+ d->kind = IComponentStore::ComponentTraits::Kind::DECODER;
+ break;
+ case C2Component::KIND_ENCODER:
+ d->kind = IComponentStore::ComponentTraits::Kind::ENCODER;
+ break;
+ case C2Component::KIND_OTHER:
+ d->kind = IComponentStore::ComponentTraits::Kind::OTHER;
+ break;
+ default:
+ LOG(DEBUG) << "Unrecognized C2Component::kind_t "
+ << "with underlying value " << underlying_value(s.kind)
+ << ".";
+ d->kind = static_cast<IComponentStore::ComponentTraits::Kind>(
+ s.kind);
+ }
+
+ d->rank = static_cast<uint32_t>(s.rank);
+
+ d->mediaType = s.mediaType;
+
+ d->aliases.resize(s.aliases.size());
+ for (size_t ix = s.aliases.size(); ix > 0; ) {
+ --ix;
+ d->aliases[ix] = s.aliases[ix];
+ }
+ return true;
+}
+
+// ComponentTraits -> C2Component::Traits, std::unique_ptr<std::vector<std::string>>
+bool objcpy(
+ C2Component::Traits* d,
+ const IComponentStore::ComponentTraits& s) {
+ d->name = s.name.c_str();
+
+ switch (s.domain) {
+ case IComponentStore::ComponentTraits::Domain::VIDEO:
+ d->domain = C2Component::DOMAIN_VIDEO;
+ break;
+ case IComponentStore::ComponentTraits::Domain::AUDIO:
+ d->domain = C2Component::DOMAIN_AUDIO;
+ break;
+ case IComponentStore::ComponentTraits::Domain::IMAGE:
+ d->domain = C2Component::DOMAIN_IMAGE;
+ break;
+ case IComponentStore::ComponentTraits::Domain::OTHER:
+ d->domain = C2Component::DOMAIN_OTHER;
+ break;
+ default:
+ LOG(DEBUG) << "Unrecognized ComponentTraits::Domain "
+ << "with underlying value " << underlying_value(s.domain)
+ << ".";
+ d->domain = static_cast<C2Component::domain_t>(s.domain);
+ }
+
+ switch (s.kind) {
+ case IComponentStore::ComponentTraits::Kind::DECODER:
+ d->kind = C2Component::KIND_DECODER;
+ break;
+ case IComponentStore::ComponentTraits::Kind::ENCODER:
+ d->kind = C2Component::KIND_ENCODER;
+ break;
+ case IComponentStore::ComponentTraits::Kind::OTHER:
+ d->kind = C2Component::KIND_OTHER;
+ break;
+ default:
+ LOG(DEBUG) << "Unrecognized ComponentTraits::Kind "
+ << "with underlying value " << underlying_value(s.kind)
+ << ".";
+ d->kind = static_cast<C2Component::kind_t>(s.kind);
+ }
+
+ d->rank = static_cast<C2Component::rank_t>(s.rank);
+ d->mediaType = s.mediaType.c_str();
+ d->aliases.resize(s.aliases.size());
+ for (size_t i = 0; i < s.aliases.size(); ++i) {
+ d->aliases[i] = s.aliases[i];
+ }
+ return true;
+}
+
+namespace /* unnamed */ {
+
+// C2ParamFieldValues -> ParamFieldValues
+bool objcpy(ParamFieldValues *d, const C2ParamFieldValues &s) {
+ if (!objcpy(&d->paramOrField, s.paramOrField)) {
+ LOG(ERROR) << "Invalid C2ParamFieldValues::paramOrField.";
+ return false;
+ }
+ if (s.values) {
+ d->values.resize(1);
+ if (!objcpy(&d->values[0], *s.values)) {
+ LOG(ERROR) << "Invalid C2ParamFieldValues::values.";
+ return false;
+ }
+ return true;
+ }
+ d->values.resize(0);
+ return true;
+}
+
+// ParamFieldValues -> C2ParamFieldValues
+bool objcpy(C2ParamFieldValues *d, const ParamFieldValues &s) {
+ d->paramOrField = C2ParamFieldBuilder(s.paramOrField);
+ if (s.values.size() == 1) {
+ d->values = std::make_unique<C2FieldSupportedValues>();
+ if (!objcpy(d->values.get(), s.values[0])) {
+ LOG(ERROR) << "Invalid ParamFieldValues::values.";
+ return false;
+ }
+ return true;
+ } else if (s.values.size() == 0) {
+ d->values.reset();
+ return true;
+ }
+ LOG(ERROR) << "Invalid ParamFieldValues: "
+ "Two or more FieldSupportedValues objects exist in "
+ "ParamFieldValues. "
+ "Only zero or one is allowed.";
+ return false;
+}
+
+} // unnamed namespace
+
+// C2SettingResult -> SettingResult
+bool objcpy(SettingResult *d, const C2SettingResult &s) {
+ switch (s.failure) {
+ case C2SettingResult::BAD_TYPE:
+ d->failure = SettingResult::Failure::BAD_TYPE;
+ break;
+ case C2SettingResult::BAD_PORT:
+ d->failure = SettingResult::Failure::BAD_PORT;
+ break;
+ case C2SettingResult::BAD_INDEX:
+ d->failure = SettingResult::Failure::BAD_INDEX;
+ break;
+ case C2SettingResult::READ_ONLY:
+ d->failure = SettingResult::Failure::READ_ONLY;
+ break;
+ case C2SettingResult::MISMATCH:
+ d->failure = SettingResult::Failure::MISMATCH;
+ break;
+ case C2SettingResult::BAD_VALUE:
+ d->failure = SettingResult::Failure::BAD_VALUE;
+ break;
+ case C2SettingResult::CONFLICT:
+ d->failure = SettingResult::Failure::CONFLICT;
+ break;
+ case C2SettingResult::UNSUPPORTED:
+ d->failure = SettingResult::Failure::UNSUPPORTED;
+ break;
+ case C2SettingResult::INFO_BAD_VALUE:
+ d->failure = SettingResult::Failure::INFO_BAD_VALUE;
+ break;
+ case C2SettingResult::INFO_CONFLICT:
+ d->failure = SettingResult::Failure::INFO_CONFLICT;
+ break;
+ default:
+ LOG(DEBUG) << "Unrecognized C2SettingResult::Failure "
+ << "with underlying value " << underlying_value(s.failure)
+ << ".";
+ d->failure = static_cast<SettingResult::Failure>(s.failure);
+ }
+ if (!objcpy(&d->field, s.field)) {
+ LOG(ERROR) << "Invalid C2SettingResult::field.";
+ return false;
+ }
+ d->conflicts.resize(s.conflicts.size());
+ size_t i = 0;
+ for (const C2ParamFieldValues& sConflict : s.conflicts) {
+ ParamFieldValues &dConflict = d->conflicts[i++];
+ if (!objcpy(&dConflict, sConflict)) {
+ LOG(ERROR) << "Invalid C2SettingResult::conflicts["
+ << i - 1 << "].";
+ return false;
+ }
+ }
+ return true;
+}
+
+// SettingResult -> std::unique_ptr<C2SettingResult>
+bool objcpy(std::unique_ptr<C2SettingResult> *d, const SettingResult &s) {
+ *d = std::unique_ptr<C2SettingResult>(new C2SettingResult {
+ .field = C2ParamFieldValues(C2ParamFieldBuilder()) });
+ if (!*d) {
+ LOG(ERROR) << "No memory for C2SettingResult.";
+ return false;
+ }
+
+ // failure
+ switch (s.failure) {
+ case SettingResult::Failure::BAD_TYPE:
+ (*d)->failure = C2SettingResult::BAD_TYPE;
+ break;
+ case SettingResult::Failure::BAD_PORT:
+ (*d)->failure = C2SettingResult::BAD_PORT;
+ break;
+ case SettingResult::Failure::BAD_INDEX:
+ (*d)->failure = C2SettingResult::BAD_INDEX;
+ break;
+ case SettingResult::Failure::READ_ONLY:
+ (*d)->failure = C2SettingResult::READ_ONLY;
+ break;
+ case SettingResult::Failure::MISMATCH:
+ (*d)->failure = C2SettingResult::MISMATCH;
+ break;
+ case SettingResult::Failure::BAD_VALUE:
+ (*d)->failure = C2SettingResult::BAD_VALUE;
+ break;
+ case SettingResult::Failure::CONFLICT:
+ (*d)->failure = C2SettingResult::CONFLICT;
+ break;
+ case SettingResult::Failure::UNSUPPORTED:
+ (*d)->failure = C2SettingResult::UNSUPPORTED;
+ break;
+ case SettingResult::Failure::INFO_BAD_VALUE:
+ (*d)->failure = C2SettingResult::INFO_BAD_VALUE;
+ break;
+ case SettingResult::Failure::INFO_CONFLICT:
+ (*d)->failure = C2SettingResult::INFO_CONFLICT;
+ break;
+ default:
+ LOG(DEBUG) << "Unrecognized SettingResult::Failure "
+ << "with underlying value " << underlying_value(s.failure)
+ << ".";
+ (*d)->failure = static_cast<C2SettingResult::Failure>(s.failure);
+ }
+
+ // field
+ if (!objcpy(&(*d)->field, s.field)) {
+ LOG(ERROR) << "Invalid SettingResult::field.";
+ return false;
+ }
+
+ // conflicts
+ (*d)->conflicts.clear();
+ (*d)->conflicts.reserve(s.conflicts.size());
+ for (const ParamFieldValues& sConflict : s.conflicts) {
+ (*d)->conflicts.emplace_back(
+ C2ParamFieldValues{ C2ParamFieldBuilder(), nullptr });
+ if (!objcpy(&(*d)->conflicts.back(), sConflict)) {
+ LOG(ERROR) << "Invalid SettingResult::conflicts.";
+ return false;
+ }
+ }
+ return true;
+}
+
+// C2ParamDescriptor -> ParamDescriptor
+bool objcpy(ParamDescriptor *d, const C2ParamDescriptor &s) {
+ d->index = static_cast<ParamIndex>(s.index());
+ d->attrib = static_cast<hidl_bitfield<ParamDescriptor::Attrib>>(
+ _C2ParamInspector::GetAttrib(s));
+ d->name = s.name();
+ copyVector<uint32_t>(&d->dependencies, s.dependencies());
+ return true;
+}
+
+// ParamDescriptor -> C2ParamDescriptor
+bool objcpy(std::shared_ptr<C2ParamDescriptor> *d, const ParamDescriptor &s) {
+ std::vector<C2Param::Index> dDependencies;
+ dDependencies.reserve(s.dependencies.size());
+ for (const ParamIndex& sDependency : s.dependencies) {
+ dDependencies.emplace_back(static_cast<uint32_t>(sDependency));
+ }
+ *d = std::make_shared<C2ParamDescriptor>(
+ C2Param::Index(static_cast<uint32_t>(s.index)),
+ static_cast<C2ParamDescriptor::attrib_t>(s.attrib),
+ C2String(s.name.c_str()),
+ std::move(dDependencies));
+ return true;
+}
+
+// C2StructDescriptor -> StructDescriptor
+bool objcpy(StructDescriptor *d, const C2StructDescriptor &s) {
+ d->type = static_cast<ParamIndex>(s.coreIndex().coreIndex());
+ d->fields.resize(s.numFields());
+ size_t i = 0;
+ for (const auto& sField : s) {
+ FieldDescriptor& dField = d->fields[i++];
+ dField.fieldId.offset = static_cast<uint32_t>(
+ _C2ParamInspector::GetOffset(sField));
+ dField.fieldId.size = static_cast<uint32_t>(
+ _C2ParamInspector::GetSize(sField));
+ dField.type = static_cast<hidl_bitfield<FieldDescriptor::Type>>(
+ sField.type());
+ dField.extent = static_cast<uint32_t>(sField.extent());
+ dField.name = static_cast<hidl_string>(sField.name());
+ const auto& sNamedValues = sField.namedValues();
+ dField.namedValues.resize(sNamedValues.size());
+ size_t j = 0;
+ for (const auto& sNamedValue : sNamedValues) {
+ FieldDescriptor::NamedValue& dNamedValue = dField.namedValues[j++];
+ dNamedValue.name = static_cast<hidl_string>(sNamedValue.first);
+ dNamedValue.value = static_cast<PrimitiveValue>(
+ sNamedValue.second.u64);
+ }
+ }
+ return true;
+}
+
+// StructDescriptor -> C2StructDescriptor
+bool objcpy(std::unique_ptr<C2StructDescriptor> *d, const StructDescriptor &s) {
+ C2Param::CoreIndex dIndex = C2Param::CoreIndex(static_cast<uint32_t>(s.type));
+ std::vector<C2FieldDescriptor> dFields;
+ dFields.reserve(s.fields.size());
+ for (const auto &sField : s.fields) {
+ C2FieldDescriptor dField = {
+ static_cast<uint32_t>(sField.type),
+ sField.extent,
+ sField.name,
+ sField.fieldId.offset,
+ sField.fieldId.size };
+ C2FieldDescriptor::NamedValuesType namedValues;
+ namedValues.reserve(sField.namedValues.size());
+ for (const auto& sNamedValue : sField.namedValues) {
+ namedValues.emplace_back(
+ sNamedValue.name,
+ C2Value::Primitive(static_cast<uint64_t>(sNamedValue.value)));
+ }
+ _C2ParamInspector::AddNamedValues(dField, std::move(namedValues));
+ dFields.emplace_back(dField);
+ }
+ *d = std::make_unique<C2StructDescriptor>(
+ _C2ParamInspector::CreateStructDescriptor(dIndex, std::move(dFields)));
+ return true;
+}
+
+namespace /* unnamed */ {
+
+// Find or add a hidl BaseBlock object from a given C2Handle* to a list and an
+// associated map.
+// Note: The handle is not cloned.
+bool _addBaseBlock(
+ uint32_t* index,
+ const C2Handle* handle,
+ std::list<BaseBlock>* baseBlocks,
+ std::map<const void*, uint32_t>* baseBlockIndices) {
+ if (!handle) {
+ LOG(ERROR) << "addBaseBlock called on a null C2Handle.";
+ return false;
+ }
+ auto it = baseBlockIndices->find(handle);
+ if (it != baseBlockIndices->end()) {
+ *index = it->second;
+ } else {
+ *index = baseBlocks->size();
+ baseBlockIndices->emplace(handle, *index);
+ baseBlocks->emplace_back();
+
+ BaseBlock &dBaseBlock = baseBlocks->back();
+ // This does not clone the handle.
+ dBaseBlock.nativeBlock(
+ reinterpret_cast<const native_handle_t*>(handle));
+
+ }
+ return true;
+}
+
+// Find or add a hidl BaseBlock object from a given BufferPoolData to a list and
+// an associated map.
+bool _addBaseBlock(
+ uint32_t* index,
+ const std::shared_ptr<BufferPoolData> bpData,
+ BufferPoolSender* bufferPoolSender,
+ std::list<BaseBlock>* baseBlocks,
+ std::map<const void*, uint32_t>* baseBlockIndices) {
+ if (!bpData) {
+ LOG(ERROR) << "addBaseBlock called on a null BufferPoolData.";
+ return false;
+ }
+ auto it = baseBlockIndices->find(bpData.get());
+ if (it != baseBlockIndices->end()) {
+ *index = it->second;
+ } else {
+ *index = baseBlocks->size();
+ baseBlockIndices->emplace(bpData.get(), *index);
+ baseBlocks->emplace_back();
+
+ BaseBlock &dBaseBlock = baseBlocks->back();
+
+ if (bufferPoolSender) {
+ BufferStatusMessage pooledBlock;
+ ResultStatus bpStatus = bufferPoolSender->send(
+ bpData,
+ &pooledBlock);
+
+ if (bpStatus != ResultStatus::OK) {
+ LOG(ERROR) << "Failed to send buffer with BufferPool. Error: "
+ << static_cast<int32_t>(bpStatus)
+ << ".";
+ return false;
+ }
+ dBaseBlock.pooledBlock(pooledBlock);
+ }
+ }
+ return true;
+}
+
+bool addBaseBlock(
+ uint32_t* index,
+ const C2Handle* handle,
+ const std::shared_ptr<const _C2BlockPoolData>& blockPoolData,
+ BufferPoolSender* bufferPoolSender,
+ std::list<BaseBlock>* baseBlocks,
+ std::map<const void*, uint32_t>* baseBlockIndices) {
+ if (!blockPoolData) {
+ // No BufferPoolData ==> NATIVE block.
+ return _addBaseBlock(
+ index, handle,
+ baseBlocks, baseBlockIndices);
+ }
+ switch (blockPoolData->getType()) {
+ case _C2BlockPoolData::TYPE_BUFFERPOOL: {
+ // BufferPoolData
+ std::shared_ptr<BufferPoolData> bpData;
+ if (!_C2BlockFactory::GetBufferPoolData(blockPoolData, &bpData)
+ || !bpData) {
+ LOG(ERROR) << "BufferPoolData unavailable in a block.";
+ return false;
+ }
+ return _addBaseBlock(
+ index, bpData,
+ bufferPoolSender, baseBlocks, baseBlockIndices);
+ }
+ case _C2BlockPoolData::TYPE_BUFFERQUEUE:
+ uint32_t gen;
+ uint64_t bqId;
+ int32_t bqSlot;
+ // Update handle if migration happened.
+ if (_C2BlockFactory::GetBufferQueueData(
+ blockPoolData, &gen, &bqId, &bqSlot)) {
+ android::MigrateNativeCodec2GrallocHandle(
+ const_cast<native_handle_t*>(handle), gen, bqId, bqSlot);
+ }
+ return _addBaseBlock(
+ index, handle,
+ baseBlocks, baseBlockIndices);
+ default:
+ LOG(ERROR) << "Unknown C2BlockPoolData type.";
+ return false;
+ }
+}
+
+// C2Fence -> hidl_handle
+// Note: File descriptors are not duplicated. The original file descriptor must
+// not be closed before the transaction is complete.
+bool objcpy(hidl_handle* d, const C2Fence& s) {
+ d->setTo(nullptr);
+ native_handle_t* handle = _C2FenceFactory::CreateNativeHandle(s);
+ if (handle) {
+ d->setTo(handle, true /* owns */);
+// } else if (!s.ready()) {
+// // TODO: we should wait for unmarshallable fences but this may not be
+// // the best place for it. We can safely ignore here as at this time
+// // all fences used here are marshallable.
+ }
+ return true;
+}
+
+// C2ConstLinearBlock -> Block
+// Note: Native handles are not duplicated. The original handles must not be
+// closed before the transaction is complete.
+bool objcpy(Block* d, const C2ConstLinearBlock& s,
+ BufferPoolSender* bufferPoolSender,
+ std::list<BaseBlock>* baseBlocks,
+ std::map<const void*, uint32_t>* baseBlockIndices) {
+ std::shared_ptr<const _C2BlockPoolData> bpData =
+ _C2BlockFactory::GetLinearBlockPoolData(s);
+ if (!addBaseBlock(&d->index, s.handle(), bpData,
+ bufferPoolSender, baseBlocks, baseBlockIndices)) {
+ LOG(ERROR) << "Invalid block data in C2ConstLinearBlock.";
+ return false;
+ }
+
+ // Create the metadata.
+ C2Hidl_RangeInfo dRangeInfo;
+ dRangeInfo.offset = static_cast<uint32_t>(s.offset());
+ dRangeInfo.length = static_cast<uint32_t>(s.size());
+ if (!createParamsBlob(&d->meta, std::vector<C2Param*>{ &dRangeInfo })) {
+ LOG(ERROR) << "Invalid range info in C2ConstLinearBlock.";
+ return false;
+ }
+
+ // Copy the fence
+ if (!objcpy(&d->fence, s.fence())) {
+ LOG(ERROR) << "Invalid C2ConstLinearBlock::fence.";
+ return false;
+ }
+ return true;
+}
+
+// C2ConstGraphicBlock -> Block
+// Note: Native handles are not duplicated. The original handles must not be
+// closed before the transaction is complete.
+bool objcpy(Block* d, const C2ConstGraphicBlock& s,
+ BufferPoolSender* bufferPoolSender,
+ std::list<BaseBlock>* baseBlocks,
+ std::map<const void*, uint32_t>* baseBlockIndices) {
+ std::shared_ptr<const _C2BlockPoolData> bpData =
+ _C2BlockFactory::GetGraphicBlockPoolData(s);
+ if (!addBaseBlock(&d->index, s.handle(), bpData,
+ bufferPoolSender, baseBlocks, baseBlockIndices)) {
+ LOG(ERROR) << "Invalid block data in C2ConstGraphicBlock.";
+ return false;
+ }
+
+ // Create the metadata.
+ C2Hidl_RectInfo dRectInfo;
+ C2Rect sRect = s.crop();
+ dRectInfo.left = static_cast<uint32_t>(sRect.left);
+ dRectInfo.top = static_cast<uint32_t>(sRect.top);
+ dRectInfo.width = static_cast<uint32_t>(sRect.width);
+ dRectInfo.height = static_cast<uint32_t>(sRect.height);
+ if (!createParamsBlob(&d->meta, std::vector<C2Param*>{ &dRectInfo })) {
+ LOG(ERROR) << "Invalid rect info in C2ConstGraphicBlock.";
+ return false;
+ }
+
+ // Copy the fence
+ if (!objcpy(&d->fence, s.fence())) {
+ LOG(ERROR) << "Invalid C2ConstGraphicBlock::fence.";
+ return false;
+ }
+ return true;
+}
+
+// C2BufferData -> Buffer
+// This function only fills in d->blocks.
+bool objcpy(Buffer* d, const C2BufferData& s,
+ BufferPoolSender* bufferPoolSender,
+ std::list<BaseBlock>* baseBlocks,
+ std::map<const void*, uint32_t>* baseBlockIndices) {
+ d->blocks.resize(
+ s.linearBlocks().size() +
+ s.graphicBlocks().size());
+ size_t i = 0;
+ for (const C2ConstLinearBlock& linearBlock : s.linearBlocks()) {
+ Block& dBlock = d->blocks[i++];
+ if (!objcpy(
+ &dBlock, linearBlock,
+ bufferPoolSender, baseBlocks, baseBlockIndices)) {
+ LOG(ERROR) << "Invalid C2BufferData::linearBlocks. "
+ << "(Destination index = " << i - 1 << ".)";
+ return false;
+ }
+ }
+ for (const C2ConstGraphicBlock& graphicBlock : s.graphicBlocks()) {
+ Block& dBlock = d->blocks[i++];
+ if (!objcpy(
+ &dBlock, graphicBlock,
+ bufferPoolSender, baseBlocks, baseBlockIndices)) {
+ LOG(ERROR) << "Invalid C2BufferData::graphicBlocks. "
+ << "(Destination index = " << i - 1 << ".)";
+ return false;
+ }
+ }
+ return true;
+}
+
+// C2Buffer -> Buffer
+bool objcpy(Buffer* d, const C2Buffer& s,
+ BufferPoolSender* bufferPoolSender,
+ std::list<BaseBlock>* baseBlocks,
+ std::map<const void*, uint32_t>* baseBlockIndices) {
+ if (!createParamsBlob(&d->info, s.info())) {
+ LOG(ERROR) << "Invalid C2Buffer::info.";
+ return false;
+ }
+ if (!objcpy(d, s.data(), bufferPoolSender, baseBlocks, baseBlockIndices)) {
+ LOG(ERROR) << "Invalid C2Buffer::data.";
+ return false;
+ }
+ return true;
+}
+
+// C2InfoBuffer -> InfoBuffer
+bool objcpy(InfoBuffer* d, const C2InfoBuffer& s,
+ BufferPoolSender* bufferPoolSender,
+ std::list<BaseBlock>* baseBlocks,
+ std::map<const void*, uint32_t>* baseBlockIndices) {
+ d->index = static_cast<ParamIndex>(s.index());
+ Buffer& dBuffer = d->buffer;
+ if (!objcpy(&dBuffer, s.data(), bufferPoolSender, baseBlocks, baseBlockIndices)) {
+ LOG(ERROR) << "Invalid C2InfoBuffer::data";
+ return false;
+ }
+ return true;
+}
+
+// C2FrameData -> FrameData
+bool objcpy(FrameData* d, const C2FrameData& s,
+ BufferPoolSender* bufferPoolSender,
+ std::list<BaseBlock>* baseBlocks,
+ std::map<const void*, uint32_t>* baseBlockIndices) {
+ d->flags = static_cast<hidl_bitfield<FrameData::Flags>>(s.flags);
+ if (!objcpy(&d->ordinal, s.ordinal)) {
+ LOG(ERROR) << "Invalid C2FrameData::ordinal.";
+ return false;
+ }
+
+ d->buffers.resize(s.buffers.size());
+ size_t i = 0;
+ for (const std::shared_ptr<C2Buffer>& sBuffer : s.buffers) {
+ Buffer& dBuffer = d->buffers[i++];
+ if (!sBuffer) {
+ // A null (pointer to) C2Buffer corresponds to a Buffer with empty
+ // info and blocks.
+ dBuffer.info.resize(0);
+ dBuffer.blocks.resize(0);
+ continue;
+ }
+ if (!objcpy(
+ &dBuffer, *sBuffer,
+ bufferPoolSender, baseBlocks, baseBlockIndices)) {
+ LOG(ERROR) << "Invalid C2FrameData::buffers["
+ << i - 1 << "].";
+ return false;
+ }
+ }
+
+ if (!createParamsBlob(&d->configUpdate, s.configUpdate)) {
+ LOG(ERROR) << "Invalid C2FrameData::configUpdate.";
+ return false;
+ }
+
+ d->infoBuffers.resize(s.infoBuffers.size());
+ i = 0;
+ for (const C2InfoBuffer& sInfoBuffer : s.infoBuffers) {
+ InfoBuffer& dInfoBuffer = d->infoBuffers[i++];
+ if (!objcpy(&dInfoBuffer, sInfoBuffer,
+ bufferPoolSender, baseBlocks, baseBlockIndices)) {
+ LOG(ERROR) << "Invalid C2FrameData::infoBuffers["
+ << i - 1 << "].";
+ return false;
+ }
+ }
+
+ return true;
+}
+
+} // unnamed namespace
+
+// DefaultBufferPoolSender's implementation
+
+DefaultBufferPoolSender::DefaultBufferPoolSender(
+ const sp<IClientManager>& receiverManager,
+ std::chrono::steady_clock::duration refreshInterval)
+ : mReceiverManager(receiverManager),
+ mRefreshInterval(refreshInterval) {
+}
+
+void DefaultBufferPoolSender::setReceiver(
+ const sp<IClientManager>& receiverManager,
+ std::chrono::steady_clock::duration refreshInterval) {
+ std::lock_guard<std::mutex> lock(mMutex);
+ if (mReceiverManager != receiverManager) {
+ mReceiverManager = receiverManager;
+ mConnections.clear();
+ }
+ mRefreshInterval = refreshInterval;
+}
+
+ResultStatus DefaultBufferPoolSender::send(
+ const std::shared_ptr<BufferPoolData>& bpData,
+ BufferStatusMessage* bpMessage) {
+ int64_t connectionId = bpData->mConnectionId;
+ if (connectionId == 0) {
+ LOG(WARNING) << "registerSender -- invalid sender connection id (0).";
+ return ResultStatus::CRITICAL_ERROR;
+ }
+ std::lock_guard<std::mutex> lock(mMutex);
+ if (!mReceiverManager) {
+ LOG(ERROR) << "No access to receiver's BufferPool.";
+ return ResultStatus::NOT_FOUND;
+ }
+ if (!mSenderManager) {
+ mSenderManager = ClientManager::getInstance();
+ if (!mSenderManager) {
+ LOG(ERROR) << "Failed to retrieve local BufferPool ClientManager.";
+ return ResultStatus::CRITICAL_ERROR;
+ }
+ }
+
+ int64_t receiverConnectionId{0};
+ auto foundConnection = mConnections.find(connectionId);
+ bool isNewConnection = foundConnection == mConnections.end();
+ std::chrono::steady_clock::time_point now =
+ std::chrono::steady_clock::now();
+ if (isNewConnection ||
+ (now - foundConnection->second.lastSent > mRefreshInterval)) {
+ // Initialize the bufferpool connection.
+ ResultStatus rs =
+ mSenderManager->registerSender(mReceiverManager,
+ connectionId,
+ &receiverConnectionId);
+ if ((rs != ResultStatus::OK) && (rs != ResultStatus::ALREADY_EXISTS)) {
+ LOG(WARNING) << "registerSender -- returned error: "
+ << static_cast<int32_t>(rs)
+ << ".";
+ return rs;
+ } else if (receiverConnectionId == 0) {
+ LOG(WARNING) << "registerSender -- "
+ "invalid receiver connection id (0).";
+ return ResultStatus::CRITICAL_ERROR;
+ } else {
+ if (isNewConnection) {
+ foundConnection = mConnections.try_emplace(
+ connectionId, receiverConnectionId, now).first;
+ } else {
+ foundConnection->second.receiverConnectionId = receiverConnectionId;
+ }
+ }
+ } else {
+ receiverConnectionId = foundConnection->second.receiverConnectionId;
+ }
+
+ uint64_t transactionId;
+ int64_t timestampUs;
+ ResultStatus rs = mSenderManager->postSend(
+ receiverConnectionId, bpData, &transactionId, ×tampUs);
+ if (rs != ResultStatus::OK) {
+ LOG(ERROR) << "ClientManager::postSend -- returned error: "
+ << static_cast<int32_t>(rs)
+ << ".";
+ mConnections.erase(foundConnection);
+ return rs;
+ }
+ if (!bpMessage) {
+ LOG(ERROR) << "Null output parameter for BufferStatusMessage.";
+ mConnections.erase(foundConnection);
+ return ResultStatus::CRITICAL_ERROR;
+ }
+ bpMessage->connectionId = receiverConnectionId;
+ bpMessage->bufferId = bpData->mId;
+ bpMessage->transactionId = transactionId;
+ bpMessage->timestampUs = timestampUs;
+ foundConnection->second.lastSent = now;
+ return rs;
+}
+
+// std::list<std::unique_ptr<C2Work>> -> WorkBundle
+bool objcpy(
+ WorkBundle* d,
+ const std::list<std::unique_ptr<C2Work>>& s,
+ BufferPoolSender* bufferPoolSender) {
+ // baseBlocks holds a list of BaseBlock objects that Blocks can refer to.
+ std::list<BaseBlock> baseBlocks;
+
+ // baseBlockIndices maps a raw pointer to native_handle_t or BufferPoolData
+ // inside baseBlocks to the corresponding index into baseBlocks. The keys
+ // (pointers) are used to identify blocks that have the same "base block" in
+ // s, a list of C2Work objects. Because baseBlocks will be copied into a
+ // hidl_vec eventually, the values of baseBlockIndices are zero-based
+ // integer indices instead of list iterators.
+ //
+ // Note that the pointers can be raw because baseBlockIndices has a shorter
+ // lifespan than all of base blocks.
+ std::map<const void*, uint32_t> baseBlockIndices;
+
+ d->works.resize(s.size());
+ size_t i = 0;
+ for (const std::unique_ptr<C2Work>& sWork : s) {
+ Work &dWork = d->works[i++];
+ if (!sWork) {
+ LOG(WARNING) << "Null C2Work encountered.";
+ continue;
+ }
+
+ // chain info is not in use currently.
+
+ // input
+ if (!objcpy(&dWork.input, sWork->input,
+ bufferPoolSender, &baseBlocks, &baseBlockIndices)) {
+ LOG(ERROR) << "Invalid C2Work::input.";
+ return false;
+ }
+
+ // worklets
+ if (sWork->worklets.size() == 0) {
+ LOG(DEBUG) << "Work with no worklets.";
+ } else {
+ // Parcel the worklets.
+ hidl_vec<Worklet> &dWorklets = dWork.worklets;
+ dWorklets.resize(sWork->worklets.size());
+ size_t j = 0;
+ for (const std::unique_ptr<C2Worklet>& sWorklet : sWork->worklets)
+ {
+ if (!sWorklet) {
+ LOG(WARNING) << "Null C2Work::worklets["
+ << j << "].";
+ continue;
+ }
+ Worklet &dWorklet = dWorklets[j++];
+
+ // component id
+ dWorklet.componentId = static_cast<uint32_t>(
+ sWorklet->component);
+
+ // tunings
+ if (!createParamsBlob(&dWorklet.tunings, sWorklet->tunings)) {
+ LOG(ERROR) << "Invalid C2Work::worklets["
+ << j - 1 << "]->tunings.";
+ return false;
+ }
+
+ // failures
+ dWorklet.failures.resize(sWorklet->failures.size());
+ size_t k = 0;
+ for (const std::unique_ptr<C2SettingResult>& sFailure :
+ sWorklet->failures) {
+ if (!sFailure) {
+ LOG(WARNING) << "Null C2Work::worklets["
+ << j - 1 << "]->failures["
+ << k << "].";
+ continue;
+ }
+ if (!objcpy(&dWorklet.failures[k++], *sFailure)) {
+ LOG(ERROR) << "Invalid C2Work::worklets["
+ << j - 1 << "]->failures["
+ << k - 1 << "].";
+ return false;
+ }
+ }
+
+ // output
+ if (!objcpy(&dWorklet.output, sWorklet->output,
+ bufferPoolSender, &baseBlocks, &baseBlockIndices)) {
+ LOG(ERROR) << "Invalid C2Work::worklets["
+ << j - 1 << "]->output.";
+ return false;
+ }
+ }
+ }
+
+ // worklets processed
+ dWork.workletsProcessed = sWork->workletsProcessed;
+
+ // result
+ dWork.result = static_cast<Status>(sWork->result);
+ }
+
+ // Copy std::list<BaseBlock> to hidl_vec<BaseBlock>.
+ {
+ d->baseBlocks.resize(baseBlocks.size());
+ size_t i = 0;
+ for (const BaseBlock& baseBlock : baseBlocks) {
+ d->baseBlocks[i++] = baseBlock;
+ }
+ }
+
+ return true;
+}
+
+namespace /* unnamed */ {
+
+struct C2BaseBlock {
+ enum type_t {
+ LINEAR,
+ GRAPHIC,
+ };
+ type_t type;
+ std::shared_ptr<C2LinearBlock> linear;
+ std::shared_ptr<C2GraphicBlock> graphic;
+};
+
+// hidl_handle -> C2Fence
+// Note: File descriptors are not duplicated. The original file descriptor must
+// not be closed before the transaction is complete.
+bool objcpy(C2Fence* d, const hidl_handle& s) {
+ const native_handle_t* handle = s.getNativeHandle();
+ *d = _C2FenceFactory::CreateFromNativeHandle(handle);
+ return true;
+}
+
+// C2LinearBlock, vector<C2Param*>, C2Fence -> C2Buffer
+bool createLinearBuffer(
+ std::shared_ptr<C2Buffer>* buffer,
+ const std::shared_ptr<C2LinearBlock>& block,
+ const std::vector<C2Param*>& meta,
+ const C2Fence& fence) {
+ // Check the block meta. It should have exactly 1 C2Info:
+ // C2Hidl_RangeInfo.
+ if ((meta.size() != 1) || !meta[0]) {
+ LOG(ERROR) << "Invalid C2LinearBlock::meta.";
+ return false;
+ }
+ if (meta[0]->size() != sizeof(C2Hidl_RangeInfo)) {
+ LOG(ERROR) << "Invalid range info in C2LinearBlock.";
+ return false;
+ }
+ C2Hidl_RangeInfo *rangeInfo =
+ reinterpret_cast<C2Hidl_RangeInfo*>(meta[0]);
+
+ // Create C2Buffer from C2LinearBlock.
+ *buffer = C2Buffer::CreateLinearBuffer(block->share(
+ rangeInfo->offset, rangeInfo->length,
+ fence));
+ if (!(*buffer)) {
+ LOG(ERROR) << "CreateLinearBuffer failed.";
+ return false;
+ }
+ return true;
+}
+
+// C2GraphicBlock, vector<C2Param*>, C2Fence -> C2Buffer
+bool createGraphicBuffer(
+ std::shared_ptr<C2Buffer>* buffer,
+ const std::shared_ptr<C2GraphicBlock>& block,
+ const std::vector<C2Param*>& meta,
+ const C2Fence& fence) {
+ // Check the block meta. It should have exactly 1 C2Info:
+ // C2Hidl_RectInfo.
+ if ((meta.size() != 1) || !meta[0]) {
+ LOG(ERROR) << "Invalid C2GraphicBlock::meta.";
+ return false;
+ }
+ if (meta[0]->size() != sizeof(C2Hidl_RectInfo)) {
+ LOG(ERROR) << "Invalid rect info in C2GraphicBlock.";
+ return false;
+ }
+ C2Hidl_RectInfo *rectInfo =
+ reinterpret_cast<C2Hidl_RectInfo*>(meta[0]);
+
+ // Create C2Buffer from C2GraphicBlock.
+ *buffer = C2Buffer::CreateGraphicBuffer(block->share(
+ C2Rect(rectInfo->width, rectInfo->height).
+ at(rectInfo->left, rectInfo->top),
+ fence));
+ if (!(*buffer)) {
+ LOG(ERROR) << "CreateGraphicBuffer failed.";
+ return false;
+ }
+ return true;
+}
+
+// Buffer -> C2Buffer
+// Note: The native handles will be cloned.
+bool objcpy(std::shared_ptr<C2Buffer>* d, const Buffer& s,
+ const std::vector<C2BaseBlock>& baseBlocks) {
+ *d = nullptr;
+
+ // Currently, a non-null C2Buffer must contain exactly 1 block.
+ if (s.blocks.size() == 0) {
+ return true;
+ } else if (s.blocks.size() != 1) {
+ LOG(ERROR) << "Invalid Buffer: "
+ "Currently, a C2Buffer must contain exactly 1 block.";
+ return false;
+ }
+
+ const Block &sBlock = s.blocks[0];
+ if (sBlock.index >= baseBlocks.size()) {
+ LOG(ERROR) << "Invalid Buffer::blocks[0].index: "
+ "Array index out of range.";
+ return false;
+ }
+ const C2BaseBlock &baseBlock = baseBlocks[sBlock.index];
+
+ // Parse meta.
+ std::vector<C2Param*> sBlockMeta;
+ if (!parseParamsBlob(&sBlockMeta, sBlock.meta)) {
+ LOG(ERROR) << "Invalid Buffer::blocks[0].meta.";
+ return false;
+ }
+
+ // Copy fence.
+ C2Fence dFence;
+ if (!objcpy(&dFence, sBlock.fence)) {
+ LOG(ERROR) << "Invalid Buffer::blocks[0].fence.";
+ return false;
+ }
+
+ // Construct a block.
+ switch (baseBlock.type) {
+ case C2BaseBlock::LINEAR:
+ if (!createLinearBuffer(d, baseBlock.linear, sBlockMeta, dFence)) {
+ LOG(ERROR) << "Invalid C2BaseBlock::linear.";
+ return false;
+ }
+ break;
+ case C2BaseBlock::GRAPHIC:
+ if (!createGraphicBuffer(d, baseBlock.graphic, sBlockMeta, dFence)) {
+ LOG(ERROR) << "Invalid C2BaseBlock::graphic.";
+ return false;
+ }
+ break;
+ default:
+ LOG(ERROR) << "Invalid C2BaseBlock::type.";
+ return false;
+ }
+
+ // Parse info
+ std::vector<C2Param*> params;
+ if (!parseParamsBlob(¶ms, s.info)) {
+ LOG(ERROR) << "Invalid Buffer::info.";
+ return false;
+ }
+ for (C2Param* param : params) {
+ if (param == nullptr) {
+ LOG(ERROR) << "Null param in Buffer::info.";
+ return false;
+ }
+ std::shared_ptr<C2Param> c2param{
+ C2Param::Copy(*param).release()};
+ if (!c2param) {
+ LOG(ERROR) << "Invalid param in Buffer::info.";
+ return false;
+ }
+ c2_status_t status =
+ (*d)->setInfo(std::static_pointer_cast<C2Info>(c2param));
+ if (status != C2_OK) {
+ LOG(ERROR) << "C2Buffer::setInfo failed.";
+ return false;
+ }
+ }
+
+ return true;
+}
+
+// InfoBuffer -> C2InfoBuffer
+bool objcpy(std::vector<C2InfoBuffer> *d, const InfoBuffer& s,
+ const std::vector<C2BaseBlock>& baseBlocks) {
+
+ // Currently, a non-null C2InfoBufer must contain exactly 1 block.
+ if (s.buffer.blocks.size() == 0) {
+ return true;
+ } else if (s.buffer.blocks.size() != 1) {
+ LOG(ERROR) << "Invalid InfoBuffer::Buffer "
+ "Currently, a C2InfoBuffer must contain exactly 1 block.";
+ return false;
+ }
+
+ const Block &sBlock = s.buffer.blocks[0];
+ if (sBlock.index >= baseBlocks.size()) {
+ LOG(ERROR) << "Invalid InfoBuffer::Buffer::blocks[0].index: "
+ "Array index out of range.";
+ return false;
+ }
+ const C2BaseBlock &baseBlock = baseBlocks[sBlock.index];
+
+ // Parse meta.
+ std::vector<C2Param*> sBlockMeta;
+ if (!parseParamsBlob(&sBlockMeta, sBlock.meta)) {
+ LOG(ERROR) << "Invalid InfoBuffer::Buffer::blocks[0].meta.";
+ return false;
+ }
+
+ // Copy fence.
+ C2Fence dFence;
+ if (!objcpy(&dFence, sBlock.fence)) {
+ LOG(ERROR) << "Invalid InfoBuffer::Buffer::blocks[0].fence.";
+ return false;
+ }
+
+ // Construct a block.
+ switch (baseBlock.type) {
+ case C2BaseBlock::LINEAR:
+ if (sBlockMeta.size() == 1 && sBlockMeta[0] != nullptr &&
+ sBlockMeta[0]->size() == sizeof(C2Hidl_RangeInfo)) {
+ C2Hidl_RangeInfo *rangeInfo =
+ reinterpret_cast<C2Hidl_RangeInfo*>(sBlockMeta[0]);
+ d->emplace_back(C2InfoBuffer::CreateLinearBuffer(
+ s.index,
+ baseBlock.linear->share(
+ rangeInfo->offset, rangeInfo->length, dFence)));
+ return true;
+ }
+ LOG(ERROR) << "Invalid Meta for C2BaseBlock::Linear InfoBuffer.";
+ break;
+ case C2BaseBlock::GRAPHIC:
+ // It's not used now
+ LOG(ERROR) << "Non-Used C2BaseBlock::type for InfoBuffer.";
+ break;
+ default:
+ LOG(ERROR) << "Invalid C2BaseBlock::type for InfoBuffer.";
+ break;
+ }
+
+ return false;
+}
+
+// FrameData -> C2FrameData
+bool objcpy(C2FrameData* d, const FrameData& s,
+ const std::vector<C2BaseBlock>& baseBlocks) {
+ d->flags = static_cast<C2FrameData::flags_t>(s.flags);
+ if (!objcpy(&d->ordinal, s.ordinal)) {
+ LOG(ERROR) << "Invalid FrameData::ordinal.";
+ return false;
+ }
+ d->buffers.clear();
+ d->buffers.reserve(s.buffers.size());
+ for (const Buffer& sBuffer : s.buffers) {
+ std::shared_ptr<C2Buffer> dBuffer;
+ if (!objcpy(&dBuffer, sBuffer, baseBlocks)) {
+ LOG(ERROR) << "Invalid FrameData::buffers.";
+ return false;
+ }
+ d->buffers.emplace_back(dBuffer);
+ }
+
+ std::vector<C2Param*> params;
+ if (!parseParamsBlob(¶ms, s.configUpdate)) {
+ LOG(ERROR) << "Invalid FrameData::configUpdate.";
+ return false;
+ }
+ d->configUpdate.clear();
+ for (C2Param* param : params) {
+ d->configUpdate.emplace_back(C2Param::Copy(*param));
+ if (!d->configUpdate.back()) {
+ LOG(ERROR) << "Unexpected error while parsing "
+ "FrameData::configUpdate.";
+ return false;
+ }
+ }
+
+ d->infoBuffers.clear();
+ if (s.infoBuffers.size() == 0) {
+ // InfoBuffer is optional
+ return true;
+ }
+ d->infoBuffers.reserve(s.infoBuffers.size());
+ for (const InfoBuffer &sInfoBuffer: s.infoBuffers) {
+ if (!objcpy(&(d->infoBuffers), sInfoBuffer, baseBlocks)) {
+ LOG(ERROR) << "Invalid Framedata::infoBuffers.";
+ return false;
+ }
+ }
+ return true;
+}
+
+// BaseBlock -> C2BaseBlock
+bool objcpy(C2BaseBlock* d, const BaseBlock& s) {
+ switch (s.getDiscriminator()) {
+ case BaseBlock::hidl_discriminator::nativeBlock: {
+ if (s.nativeBlock() == nullptr) {
+ LOG(ERROR) << "Null BaseBlock::nativeBlock handle";
+ return false;
+ }
+ native_handle_t* sHandle =
+ native_handle_clone(s.nativeBlock());
+ if (sHandle == nullptr) {
+ LOG(ERROR) << "Null BaseBlock::nativeBlock.";
+ return false;
+ }
+ const C2Handle *sC2Handle =
+ reinterpret_cast<const C2Handle*>(sHandle);
+
+ d->linear = _C2BlockFactory::CreateLinearBlock(sC2Handle);
+ if (d->linear) {
+ d->type = C2BaseBlock::LINEAR;
+ return true;
+ }
+
+ d->graphic = _C2BlockFactory::CreateGraphicBlock(sC2Handle);
+ if (d->graphic) {
+ d->type = C2BaseBlock::GRAPHIC;
+ return true;
+ }
+
+ LOG(ERROR) << "Unknown handle type in BaseBlock::nativeBlock.";
+ if (sHandle) {
+ native_handle_close(sHandle);
+ native_handle_delete(sHandle);
+ }
+ return false;
+ }
+ case BaseBlock::hidl_discriminator::pooledBlock: {
+ const BufferStatusMessage &bpMessage =
+ s.pooledBlock();
+ sp<ClientManager> bp = ClientManager::getInstance();
+ std::shared_ptr<BufferPoolData> bpData;
+ native_handle_t *cHandle;
+ ResultStatus bpStatus = bp->receive(
+ bpMessage.connectionId,
+ bpMessage.transactionId,
+ bpMessage.bufferId,
+ bpMessage.timestampUs,
+ &cHandle,
+ &bpData);
+ if (bpStatus != ResultStatus::OK) {
+ LOG(ERROR) << "Failed to receive buffer from bufferpool -- "
+ << "resultStatus = " << underlying_value(bpStatus)
+ << ".";
+ return false;
+ } else if (!bpData) {
+ LOG(ERROR) << "No data in bufferpool transaction.";
+ return false;
+ }
+
+ d->linear = _C2BlockFactory::CreateLinearBlock(cHandle, bpData);
+ if (d->linear) {
+ d->type = C2BaseBlock::LINEAR;
+ return true;
+ }
+
+ d->graphic = _C2BlockFactory::CreateGraphicBlock(cHandle, bpData);
+ if (d->graphic) {
+ d->type = C2BaseBlock::GRAPHIC;
+ return true;
+ }
+ if (cHandle) {
+ // Though we got cloned handle, creating block failed.
+ native_handle_close(cHandle);
+ native_handle_delete(cHandle);
+ }
+
+ LOG(ERROR) << "Unknown handle type in BaseBlock::pooledBlock.";
+ return false;
+ }
+ default:
+ LOG(ERROR) << "Unrecognized BaseBlock's discriminator with "
+ << "underlying value "
+ << underlying_value(s.getDiscriminator()) << ".";
+ return false;
+ }
+}
+
+} // unnamed namespace
+
+// WorkBundle -> std::list<std::unique_ptr<C2Work>>
+bool objcpy(std::list<std::unique_ptr<C2Work>>* d, const WorkBundle& s) {
+ // Convert BaseBlocks to C2BaseBlocks.
+ std::vector<C2BaseBlock> dBaseBlocks(s.baseBlocks.size());
+ for (size_t i = 0; i < s.baseBlocks.size(); ++i) {
+ if (!objcpy(&dBaseBlocks[i], s.baseBlocks[i])) {
+ LOG(ERROR) << "Invalid WorkBundle::baseBlocks["
+ << i << "].";
+ return false;
+ }
+ }
+
+ d->clear();
+ for (const Work& sWork : s.works) {
+ d->emplace_back(std::make_unique<C2Work>());
+ C2Work& dWork = *d->back();
+
+ // chain info is not in use currently.
+
+ // input
+ if (!objcpy(&dWork.input, sWork.input, dBaseBlocks)) {
+ LOG(ERROR) << "Invalid Work::input.";
+ return false;
+ }
+
+ // worklet(s)
+ dWork.worklets.clear();
+ for (const Worklet& sWorklet : sWork.worklets) {
+ std::unique_ptr<C2Worklet> dWorklet = std::make_unique<C2Worklet>();
+
+ // component id
+ dWorklet->component = static_cast<c2_node_id_t>(
+ sWorklet.componentId);
+
+ // tunings
+ if (!copyParamsFromBlob(&dWorklet->tunings, sWorklet.tunings)) {
+ LOG(ERROR) << "Invalid Worklet::tunings";
+ return false;
+ }
+
+ // failures
+ dWorklet->failures.clear();
+ dWorklet->failures.reserve(sWorklet.failures.size());
+ for (const SettingResult& sFailure : sWorklet.failures) {
+ std::unique_ptr<C2SettingResult> dFailure;
+ if (!objcpy(&dFailure, sFailure)) {
+ LOG(ERROR) << "Invalid Worklet::failures.";
+ return false;
+ }
+ dWorklet->failures.emplace_back(std::move(dFailure));
+ }
+
+ // output
+ if (!objcpy(&dWorklet->output, sWorklet.output, dBaseBlocks)) {
+ LOG(ERROR) << "Invalid Worklet::output.";
+ return false;
+ }
+
+ dWork.worklets.emplace_back(std::move(dWorklet));
+ }
+
+ // workletsProcessed
+ dWork.workletsProcessed = sWork.workletsProcessed;
+
+ // result
+ dWork.result = static_cast<c2_status_t>(sWork.result);
+ }
+
+ return true;
+}
+
+constexpr size_t PARAMS_ALIGNMENT = 8; // 64-bit alignment
+static_assert(PARAMS_ALIGNMENT % alignof(C2Param) == 0, "C2Param alignment mismatch");
+static_assert(PARAMS_ALIGNMENT % alignof(C2Info) == 0, "C2Param alignment mismatch");
+static_assert(PARAMS_ALIGNMENT % alignof(C2Tuning) == 0, "C2Param alignment mismatch");
+
+// Params -> std::vector<C2Param*>
+bool parseParamsBlob(std::vector<C2Param*> *params, const hidl_vec<uint8_t> &blob) {
+ // assuming blob is const here
+ size_t size = blob.size();
+ size_t ix = 0;
+ size_t old_ix = 0;
+ const uint8_t *data = blob.data();
+ C2Param *p = nullptr;
+
+ do {
+ p = C2ParamUtils::ParseFirst(data + ix, size - ix);
+ if (p) {
+ params->emplace_back(p);
+ old_ix = ix;
+ ix += p->size();
+ ix = align(ix, PARAMS_ALIGNMENT);
+ if (ix <= old_ix || ix > size) {
+ android_errorWriteLog(0x534e4554, "238083570");
+ break;
+ }
+ }
+ } while (p);
+
+ if (ix != size) {
+ LOG(ERROR) << "parseParamsBlob -- inconsistent sizes.";
+ return false;
+ }
+ return true;
+}
+
+namespace /* unnamed */ {
+
+/**
+ * Concatenates a list of C2Params into a params blob. T is a container type
+ * whose member type is compatible with C2Param*.
+ *
+ * \param[out] blob target blob
+ * \param[in] params parameters to concatenate
+ * \retval C2_OK if the blob was successfully created
+ * \retval C2_BAD_VALUE if the blob was not successful created (this only
+ * happens if the parameters were not const)
+ */
+template <typename T>
+bool _createParamsBlob(hidl_vec<uint8_t> *blob, const T ¶ms) {
+ // assuming the parameter values are const
+ size_t size = 0;
+ for (const auto &p : params) {
+ if (!p) {
+ continue;
+ }
+ size += p->size();
+ size = align(size, PARAMS_ALIGNMENT);
+ }
+ blob->resize(size);
+ size_t ix = 0;
+ for (const auto &p : params) {
+ if (!p) {
+ continue;
+ }
+ // NEVER overwrite even if param values (e.g. size) changed
+ size_t paramSize = std::min(p->size(), size - ix);
+ std::copy(
+ reinterpret_cast<const uint8_t*>(&*p),
+ reinterpret_cast<const uint8_t*>(&*p) + paramSize,
+ &(*blob)[ix]);
+ ix += paramSize;
+ ix = align(ix, PARAMS_ALIGNMENT);
+ }
+ blob->resize(ix);
+ if (ix != size) {
+ LOG(ERROR) << "createParamsBlob -- inconsistent sizes.";
+ return false;
+ }
+ return true;
+}
+
+/**
+ * Parses a params blob and create a vector of new T objects that contain copies
+ * of the params in the blob. T is C2Param or its compatible derived class.
+ *
+ * \param[out] params the resulting vector
+ * \param[in] blob parameter blob to parse
+ * \retval C2_OK if the full blob was parsed and params was constructed
+ * \retval C2_BAD_VALUE otherwise
+ */
+template <typename T>
+bool _copyParamsFromBlob(
+ std::vector<std::unique_ptr<T>>* params,
+ Params blob) {
+
+ std::vector<C2Param*> paramPointers;
+ if (!parseParamsBlob(¶mPointers, blob)) {
+ LOG(ERROR) << "copyParamsFromBlob -- failed to parse.";
+ return false;
+ }
+
+ params->resize(paramPointers.size());
+ size_t i = 0;
+ for (C2Param* const& paramPointer : paramPointers) {
+ if (!paramPointer) {
+ LOG(ERROR) << "copyParamsFromBlob -- null paramPointer.";
+ return false;
+ }
+ (*params)[i++].reset(reinterpret_cast<T*>(
+ C2Param::Copy(*paramPointer).release()));
+ }
+ return true;
+}
+
+} // unnamed namespace
+
+// std::vector<const C2Param*> -> Params
+bool createParamsBlob(
+ hidl_vec<uint8_t> *blob,
+ const std::vector<const C2Param*> ¶ms) {
+ return _createParamsBlob(blob, params);
+}
+
+// std::vector<C2Param*> -> Params
+bool createParamsBlob(
+ hidl_vec<uint8_t> *blob,
+ const std::vector<C2Param*> ¶ms) {
+ return _createParamsBlob(blob, params);
+}
+
+// std::vector<std::unique_ptr<C2Param>> -> Params
+bool createParamsBlob(
+ hidl_vec<uint8_t> *blob,
+ const std::vector<std::unique_ptr<C2Param>> ¶ms) {
+ return _createParamsBlob(blob, params);
+}
+
+// std::vector<std::unique_ptr<C2Tuning>> -> Params
+bool createParamsBlob(
+ hidl_vec<uint8_t> *blob,
+ const std::vector<std::unique_ptr<C2Tuning>> ¶ms) {
+ return _createParamsBlob(blob, params);
+}
+
+// std::vector<std::shared_ptr<const C2Info>> -> Params
+bool createParamsBlob(
+ hidl_vec<uint8_t> *blob,
+ const std::vector<std::shared_ptr<const C2Info>> ¶ms) {
+ return _createParamsBlob(blob, params);
+}
+
+// Params -> std::vector<std::unique_ptr<C2Param>>
+bool copyParamsFromBlob(
+ std::vector<std::unique_ptr<C2Param>>* params,
+ Params blob) {
+ return _copyParamsFromBlob(params, blob);
+}
+
+// Params -> std::vector<std::unique_ptr<C2Tuning>>
+bool copyParamsFromBlob(
+ std::vector<std::unique_ptr<C2Tuning>>* params,
+ Params blob) {
+ return _copyParamsFromBlob(params, blob);
+}
+
+// Params -> update std::vector<std::unique_ptr<C2Param>>
+bool updateParamsFromBlob(
+ const std::vector<C2Param*>& params,
+ const Params& blob) {
+ std::unordered_map<uint32_t, C2Param*> index2param;
+ for (C2Param* const& param : params) {
+ if (!param) {
+ LOG(ERROR) << "updateParamsFromBlob -- null output param.";
+ return false;
+ }
+ if (index2param.find(param->index()) == index2param.end()) {
+ index2param.emplace(param->index(), param);
+ }
+ }
+
+ std::vector<C2Param*> paramPointers;
+ if (!parseParamsBlob(¶mPointers, blob)) {
+ LOG(ERROR) << "updateParamsFromBlob -- failed to parse.";
+ return false;
+ }
+
+ for (C2Param* const& paramPointer : paramPointers) {
+ if (!paramPointer) {
+ LOG(ERROR) << "updateParamsFromBlob -- null input param.";
+ return false;
+ }
+ decltype(index2param)::iterator i = index2param.find(
+ paramPointer->index());
+ if (i == index2param.end()) {
+ LOG(DEBUG) << "updateParamsFromBlob -- index "
+ << paramPointer->index() << " not found. Skipping...";
+ continue;
+ }
+ if (!i->second->updateFrom(*paramPointer)) {
+ LOG(ERROR) << "updateParamsFromBlob -- size mismatch: "
+ << params.size() << " vs " << paramPointer->size()
+ << " (index = " << i->first << ").";
+ return false;
+ }
+ }
+ return true;
+}
+
+// Convert BufferPool ResultStatus to c2_status_t.
+c2_status_t toC2Status(ResultStatus rs) {
+ switch (rs) {
+ case ResultStatus::OK:
+ return C2_OK;
+ case ResultStatus::NO_MEMORY:
+ return C2_NO_MEMORY;
+ case ResultStatus::ALREADY_EXISTS:
+ return C2_DUPLICATE;
+ case ResultStatus::NOT_FOUND:
+ return C2_NOT_FOUND;
+ case ResultStatus::CRITICAL_ERROR:
+ return C2_CORRUPTED;
+ default:
+ LOG(WARNING) << "Unrecognized BufferPool ResultStatus: "
+ << static_cast<int32_t>(rs) << ".";
+ return C2_CORRUPTED;
+ }
+}
+
+namespace /* unnamed */ {
+
+template <typename BlockProcessor>
+void forEachBlock(C2FrameData& frameData,
+ BlockProcessor process) {
+ for (const std::shared_ptr<C2Buffer>& buffer : frameData.buffers) {
+ if (buffer) {
+ for (const C2ConstGraphicBlock& block :
+ buffer->data().graphicBlocks()) {
+ process(block);
+ }
+ }
+ }
+}
+
+template <typename BlockProcessor>
+void forEachBlock(const std::list<std::unique_ptr<C2Work>>& workList,
+ BlockProcessor process,
+ bool processInput, bool processOutput) {
+ for (const std::unique_ptr<C2Work>& work : workList) {
+ if (!work) {
+ continue;
+ }
+ if (processInput) {
+ forEachBlock(work->input, process);
+ }
+ if (processOutput) {
+ for (const std::unique_ptr<C2Worklet>& worklet : work->worklets) {
+ if (worklet) {
+ forEachBlock(worklet->output,
+ process);
+ }
+ }
+ }
+ }
+}
+
+} // unnamed namespace
+
+bool beginTransferBufferQueueBlock(const C2ConstGraphicBlock& block) {
+ std::shared_ptr<_C2BlockPoolData> data =
+ _C2BlockFactory::GetGraphicBlockPoolData(block);
+ if (data && _C2BlockFactory::GetBufferQueueData(data)) {
+ _C2BlockFactory::BeginTransferBlockToClient(data);
+ return true;
+ }
+ return false;
+}
+
+void beginTransferBufferQueueBlocks(
+ const std::list<std::unique_ptr<C2Work>>& workList,
+ bool processInput, bool processOutput) {
+ forEachBlock(workList, beginTransferBufferQueueBlock,
+ processInput, processOutput);
+}
+
+bool endTransferBufferQueueBlock(
+ const C2ConstGraphicBlock& block,
+ bool transfer) {
+ std::shared_ptr<_C2BlockPoolData> data =
+ _C2BlockFactory::GetGraphicBlockPoolData(block);
+ if (data && _C2BlockFactory::GetBufferQueueData(data)) {
+ _C2BlockFactory::EndTransferBlockToClient(data, transfer);
+ return true;
+ }
+ return false;
+}
+
+void endTransferBufferQueueBlocks(
+ const std::list<std::unique_ptr<C2Work>>& workList,
+ bool transfer,
+ bool processInput, bool processOutput) {
+ forEachBlock(workList,
+ std::bind(endTransferBufferQueueBlock,
+ std::placeholders::_1, transfer),
+ processInput, processOutput);
+}
+
+bool displayBufferQueueBlock(const C2ConstGraphicBlock& block) {
+ std::shared_ptr<_C2BlockPoolData> data =
+ _C2BlockFactory::GetGraphicBlockPoolData(block);
+ if (data && _C2BlockFactory::GetBufferQueueData(data)) {
+ _C2BlockFactory::DisplayBlockToBufferQueue(data);
+ return true;
+ }
+ return false;
+}
+
+} // namespace utils
+} // namespace V1_0
+} // namespace c2
+} // namespace media
+} // namespace hardware
+} // namespace android
+
diff --git a/media/codec2/hal/common/include/codec2/common/ParamTypes.h b/media/codec2/hal/common/include/codec2/common/ParamTypes.h
new file mode 100644
index 0000000..319ba62
--- /dev/null
+++ b/media/codec2/hal/common/include/codec2/common/ParamTypes.h
@@ -0,0 +1,1928 @@
+/*
+ * 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-types"
+#include <android-base/logging.h>
+
+#include <codec2/hidl/1.0/types.h>
+#include <media/stagefright/foundation/AUtils.h>
+
+#include <C2AllocatorIon.h>
+#include <C2AllocatorGralloc.h>
+#include <C2BlockInternal.h>
+#include <C2Buffer.h>
+#include <C2Component.h>
+#include <C2FenceFactory.h>
+#include <C2Param.h>
+#include <C2ParamInternal.h>
+#include <C2PlatformSupport.h>
+#include <C2Work.h>
+#include <util/C2ParamUtils.h>
+
+#include <algorithm>
+#include <functional>
+#include <iomanip>
+#include <unordered_map>
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace c2 {
+namespace V1_0 {
+namespace utils {
+
+using ::android::hardware::Return;
+using ::android::hardware::media::bufferpool::BufferPoolData;
+using ::android::hardware::media::bufferpool::V2_0::BufferStatusMessage;
+using ::android::hardware::media::bufferpool::V2_0::ResultStatus;
+using ::android::hardware::media::bufferpool::V2_0::implementation::
+ ClientManager;
+using ::android::hardware::media::bufferpool::V2_0::implementation::
+ TransactionId;
+
+const char* asString(Status status, const char* def) {
+ return asString(static_cast<c2_status_t>(status), def);
+}
+
+namespace /* unnamed */ {
+
+template <typename EnumClass>
+typename std::underlying_type<EnumClass>::type underlying_value(
+ EnumClass x) {
+ return static_cast<typename std::underlying_type<EnumClass>::type>(x);
+}
+
+template <typename Common, typename DstVector, typename SrcVector>
+void copyVector(DstVector* d, const SrcVector& s) {
+ static_assert(sizeof(Common) == sizeof(decltype((*d)[0])),
+ "DstVector's component size does not match Common");
+ static_assert(sizeof(Common) == sizeof(decltype(s[0])),
+ "SrcVector's component size does not match Common");
+ d->resize(s.size());
+ std::copy(
+ reinterpret_cast<const Common*>(&s[0]),
+ reinterpret_cast<const Common*>(&s[0] + s.size()),
+ reinterpret_cast<Common*>(&(*d)[0]));
+}
+
+// C2ParamField -> ParamField
+bool objcpy(ParamField *d, const C2ParamField &s) {
+ d->index = static_cast<ParamIndex>(_C2ParamInspector::GetIndex(s));
+ d->fieldId.offset = static_cast<uint32_t>(_C2ParamInspector::GetOffset(s));
+ d->fieldId.size = static_cast<uint32_t>(_C2ParamInspector::GetSize(s));
+ return true;
+}
+
+struct C2ParamFieldBuilder : public C2ParamField {
+ C2ParamFieldBuilder() : C2ParamField(
+ static_cast<C2Param::Index>(static_cast<uint32_t>(0)), 0, 0) {
+ }
+ // ParamField -> C2ParamField
+ C2ParamFieldBuilder(const ParamField& s) : C2ParamField(
+ static_cast<C2Param::Index>(static_cast<uint32_t>(s.index)),
+ static_cast<uint32_t>(s.fieldId.offset),
+ static_cast<uint32_t>(s.fieldId.size)) {
+ }
+};
+
+// C2WorkOrdinalStruct -> WorkOrdinal
+bool objcpy(WorkOrdinal *d, const C2WorkOrdinalStruct &s) {
+ d->frameIndex = static_cast<uint64_t>(s.frameIndex.peeku());
+ d->timestampUs = static_cast<uint64_t>(s.timestamp.peeku());
+ d->customOrdinal = static_cast<uint64_t>(s.customOrdinal.peeku());
+ return true;
+}
+
+// WorkOrdinal -> C2WorkOrdinalStruct
+bool objcpy(C2WorkOrdinalStruct *d, const WorkOrdinal &s) {
+ d->frameIndex = c2_cntr64_t(s.frameIndex);
+ d->timestamp = c2_cntr64_t(s.timestampUs);
+ d->customOrdinal = c2_cntr64_t(s.customOrdinal);
+ return true;
+}
+
+// C2FieldSupportedValues::range's type -> ValueRange
+bool objcpy(
+ ValueRange* d,
+ const decltype(C2FieldSupportedValues::range)& s) {
+ d->min = static_cast<PrimitiveValue>(s.min.u64);
+ d->max = static_cast<PrimitiveValue>(s.max.u64);
+ d->step = static_cast<PrimitiveValue>(s.step.u64);
+ d->num = static_cast<PrimitiveValue>(s.num.u64);
+ d->denom = static_cast<PrimitiveValue>(s.denom.u64);
+ return true;
+}
+
+// C2FieldSupportedValues -> FieldSupportedValues
+bool objcpy(FieldSupportedValues *d, const C2FieldSupportedValues &s) {
+ switch (s.type) {
+ case C2FieldSupportedValues::EMPTY: {
+ d->empty(::android::hidl::safe_union::V1_0::Monostate{});
+ break;
+ }
+ case C2FieldSupportedValues::RANGE: {
+ ValueRange range{};
+ if (!objcpy(&range, s.range)) {
+ LOG(ERROR) << "Invalid C2FieldSupportedValues::range.";
+ d->range(range);
+ return false;
+ }
+ d->range(range);
+ break;
+ }
+ case C2FieldSupportedValues::VALUES: {
+ hidl_vec<PrimitiveValue> values;
+ copyVector<uint64_t>(&values, s.values);
+ d->values(values);
+ break;
+ }
+ case C2FieldSupportedValues::FLAGS: {
+ hidl_vec<PrimitiveValue> flags;
+ copyVector<uint64_t>(&flags, s.values);
+ d->flags(flags);
+ break;
+ }
+ default:
+ LOG(DEBUG) << "Unrecognized C2FieldSupportedValues::type_t "
+ << "with underlying value " << underlying_value(s.type)
+ << ".";
+ return false;
+ }
+ return true;
+}
+
+// ValueRange -> C2FieldSupportedValues::range's type
+bool objcpy(
+ decltype(C2FieldSupportedValues::range)* d,
+ const ValueRange& s) {
+ d->min.u64 = static_cast<uint64_t>(s.min);
+ d->max.u64 = static_cast<uint64_t>(s.max);
+ d->step.u64 = static_cast<uint64_t>(s.step);
+ d->num.u64 = static_cast<uint64_t>(s.num);
+ d->denom.u64 = static_cast<uint64_t>(s.denom);
+ return true;
+}
+
+// FieldSupportedValues -> C2FieldSupportedValues
+bool objcpy(C2FieldSupportedValues *d, const FieldSupportedValues &s) {
+ switch (s.getDiscriminator()) {
+ case FieldSupportedValues::hidl_discriminator::empty: {
+ d->type = C2FieldSupportedValues::EMPTY;
+ break;
+ }
+ case FieldSupportedValues::hidl_discriminator::range: {
+ d->type = C2FieldSupportedValues::RANGE;
+ if (!objcpy(&d->range, s.range())) {
+ LOG(ERROR) << "Invalid FieldSupportedValues::range.";
+ return false;
+ }
+ d->values.resize(0);
+ break;
+ }
+ case FieldSupportedValues::hidl_discriminator::values: {
+ d->type = C2FieldSupportedValues::VALUES;
+ copyVector<uint64_t>(&d->values, s.values());
+ break;
+ }
+ case FieldSupportedValues::hidl_discriminator::flags: {
+ d->type = C2FieldSupportedValues::FLAGS;
+ copyVector<uint64_t>(&d->values, s.flags());
+ break;
+ }
+ default:
+ LOG(WARNING) << "Unrecognized FieldSupportedValues::getDiscriminator()";
+ return false;
+ }
+ return true;
+}
+
+} // unnamed namespace
+
+// C2FieldSupportedValuesQuery -> FieldSupportedValuesQuery
+bool objcpy(
+ FieldSupportedValuesQuery* d,
+ const C2FieldSupportedValuesQuery& s) {
+ if (!objcpy(&d->field, s.field())) {
+ LOG(ERROR) << "Invalid C2FieldSupportedValuesQuery::field.";
+ return false;
+ }
+ switch (s.type()) {
+ case C2FieldSupportedValuesQuery::POSSIBLE:
+ d->type = FieldSupportedValuesQuery::Type::POSSIBLE;
+ break;
+ case C2FieldSupportedValuesQuery::CURRENT:
+ d->type = FieldSupportedValuesQuery::Type::CURRENT;
+ break;
+ default:
+ LOG(DEBUG) << "Unrecognized C2FieldSupportedValuesQuery::type_t "
+ << "with underlying value " << underlying_value(s.type())
+ << ".";
+ d->type = static_cast<FieldSupportedValuesQuery::Type>(s.type());
+ }
+ return true;
+}
+
+// FieldSupportedValuesQuery -> C2FieldSupportedValuesQuery
+bool objcpy(
+ C2FieldSupportedValuesQuery* d,
+ const FieldSupportedValuesQuery& s) {
+ C2FieldSupportedValuesQuery::type_t dType;
+ switch (s.type) {
+ case FieldSupportedValuesQuery::Type::POSSIBLE:
+ dType = C2FieldSupportedValuesQuery::POSSIBLE;
+ break;
+ case FieldSupportedValuesQuery::Type::CURRENT:
+ dType = C2FieldSupportedValuesQuery::CURRENT;
+ break;
+ default:
+ LOG(DEBUG) << "Unrecognized FieldSupportedValuesQuery::Type "
+ << "with underlying value " << underlying_value(s.type)
+ << ".";
+ dType = static_cast<C2FieldSupportedValuesQuery::type_t>(s.type);
+ }
+ *d = C2FieldSupportedValuesQuery(C2ParamFieldBuilder(s.field), dType);
+ return true;
+}
+
+// C2FieldSupportedValuesQuery -> FieldSupportedValuesQueryResult
+bool objcpy(
+ FieldSupportedValuesQueryResult* d,
+ const C2FieldSupportedValuesQuery& s) {
+ d->status = static_cast<Status>(s.status);
+ return objcpy(&d->values, s.values);
+}
+
+// FieldSupportedValuesQuery, FieldSupportedValuesQueryResult ->
+// C2FieldSupportedValuesQuery
+bool objcpy(
+ C2FieldSupportedValuesQuery* d,
+ const FieldSupportedValuesQuery& sq,
+ const FieldSupportedValuesQueryResult& sr) {
+ if (!objcpy(d, sq)) {
+ LOG(ERROR) << "Invalid FieldSupportedValuesQuery.";
+ return false;
+ }
+ d->status = static_cast<c2_status_t>(sr.status);
+ if (!objcpy(&d->values, sr.values)) {
+ LOG(ERROR) << "Invalid FieldSupportedValuesQueryResult::values.";
+ return false;
+ }
+ return true;
+}
+
+// C2Component::Traits -> IComponentStore::ComponentTraits
+bool objcpy(
+ IComponentStore::ComponentTraits *d,
+ const C2Component::Traits &s) {
+ d->name = s.name;
+
+ switch (s.domain) {
+ case C2Component::DOMAIN_VIDEO:
+ d->domain = IComponentStore::ComponentTraits::Domain::VIDEO;
+ break;
+ case C2Component::DOMAIN_AUDIO:
+ d->domain = IComponentStore::ComponentTraits::Domain::AUDIO;
+ break;
+ case C2Component::DOMAIN_IMAGE:
+ d->domain = IComponentStore::ComponentTraits::Domain::IMAGE;
+ break;
+ case C2Component::DOMAIN_OTHER:
+ d->domain = IComponentStore::ComponentTraits::Domain::OTHER;
+ break;
+ default:
+ LOG(DEBUG) << "Unrecognized C2Component::domain_t "
+ << "with underlying value " << underlying_value(s.domain)
+ << ".";
+ d->domain = static_cast<IComponentStore::ComponentTraits::Domain>(
+ s.domain);
+ }
+
+ switch (s.kind) {
+ case C2Component::KIND_DECODER:
+ d->kind = IComponentStore::ComponentTraits::Kind::DECODER;
+ break;
+ case C2Component::KIND_ENCODER:
+ d->kind = IComponentStore::ComponentTraits::Kind::ENCODER;
+ break;
+ case C2Component::KIND_OTHER:
+ d->kind = IComponentStore::ComponentTraits::Kind::OTHER;
+ break;
+ default:
+ LOG(DEBUG) << "Unrecognized C2Component::kind_t "
+ << "with underlying value " << underlying_value(s.kind)
+ << ".";
+ d->kind = static_cast<IComponentStore::ComponentTraits::Kind>(
+ s.kind);
+ }
+
+ d->rank = static_cast<uint32_t>(s.rank);
+
+ d->mediaType = s.mediaType;
+
+ d->aliases.resize(s.aliases.size());
+ for (size_t ix = s.aliases.size(); ix > 0; ) {
+ --ix;
+ d->aliases[ix] = s.aliases[ix];
+ }
+ return true;
+}
+
+// ComponentTraits -> C2Component::Traits, std::unique_ptr<std::vector<std::string>>
+bool objcpy(
+ C2Component::Traits* d,
+ const IComponentStore::ComponentTraits& s) {
+ d->name = s.name.c_str();
+
+ switch (s.domain) {
+ case IComponentStore::ComponentTraits::Domain::VIDEO:
+ d->domain = C2Component::DOMAIN_VIDEO;
+ break;
+ case IComponentStore::ComponentTraits::Domain::AUDIO:
+ d->domain = C2Component::DOMAIN_AUDIO;
+ break;
+ case IComponentStore::ComponentTraits::Domain::IMAGE:
+ d->domain = C2Component::DOMAIN_IMAGE;
+ break;
+ case IComponentStore::ComponentTraits::Domain::OTHER:
+ d->domain = C2Component::DOMAIN_OTHER;
+ break;
+ default:
+ LOG(DEBUG) << "Unrecognized ComponentTraits::Domain "
+ << "with underlying value " << underlying_value(s.domain)
+ << ".";
+ d->domain = static_cast<C2Component::domain_t>(s.domain);
+ }
+
+ switch (s.kind) {
+ case IComponentStore::ComponentTraits::Kind::DECODER:
+ d->kind = C2Component::KIND_DECODER;
+ break;
+ case IComponentStore::ComponentTraits::Kind::ENCODER:
+ d->kind = C2Component::KIND_ENCODER;
+ break;
+ case IComponentStore::ComponentTraits::Kind::OTHER:
+ d->kind = C2Component::KIND_OTHER;
+ break;
+ default:
+ LOG(DEBUG) << "Unrecognized ComponentTraits::Kind "
+ << "with underlying value " << underlying_value(s.kind)
+ << ".";
+ d->kind = static_cast<C2Component::kind_t>(s.kind);
+ }
+
+ d->rank = static_cast<C2Component::rank_t>(s.rank);
+ d->mediaType = s.mediaType.c_str();
+ d->aliases.resize(s.aliases.size());
+ for (size_t i = 0; i < s.aliases.size(); ++i) {
+ d->aliases[i] = s.aliases[i];
+ }
+ return true;
+}
+
+namespace /* unnamed */ {
+
+// C2ParamFieldValues -> ParamFieldValues
+bool objcpy(ParamFieldValues *d, const C2ParamFieldValues &s) {
+ if (!objcpy(&d->paramOrField, s.paramOrField)) {
+ LOG(ERROR) << "Invalid C2ParamFieldValues::paramOrField.";
+ return false;
+ }
+ if (s.values) {
+ d->values.resize(1);
+ if (!objcpy(&d->values[0], *s.values)) {
+ LOG(ERROR) << "Invalid C2ParamFieldValues::values.";
+ return false;
+ }
+ return true;
+ }
+ d->values.resize(0);
+ return true;
+}
+
+// ParamFieldValues -> C2ParamFieldValues
+bool objcpy(C2ParamFieldValues *d, const ParamFieldValues &s) {
+ d->paramOrField = C2ParamFieldBuilder(s.paramOrField);
+ if (s.values.size() == 1) {
+ d->values = std::make_unique<C2FieldSupportedValues>();
+ if (!objcpy(d->values.get(), s.values[0])) {
+ LOG(ERROR) << "Invalid ParamFieldValues::values.";
+ return false;
+ }
+ return true;
+ } else if (s.values.size() == 0) {
+ d->values.reset();
+ return true;
+ }
+ LOG(ERROR) << "Invalid ParamFieldValues: "
+ "Two or more FieldSupportedValues objects exist in "
+ "ParamFieldValues. "
+ "Only zero or one is allowed.";
+ return false;
+}
+
+} // unnamed namespace
+
+// C2SettingResult -> SettingResult
+bool objcpy(SettingResult *d, const C2SettingResult &s) {
+ switch (s.failure) {
+ case C2SettingResult::BAD_TYPE:
+ d->failure = SettingResult::Failure::BAD_TYPE;
+ break;
+ case C2SettingResult::BAD_PORT:
+ d->failure = SettingResult::Failure::BAD_PORT;
+ break;
+ case C2SettingResult::BAD_INDEX:
+ d->failure = SettingResult::Failure::BAD_INDEX;
+ break;
+ case C2SettingResult::READ_ONLY:
+ d->failure = SettingResult::Failure::READ_ONLY;
+ break;
+ case C2SettingResult::MISMATCH:
+ d->failure = SettingResult::Failure::MISMATCH;
+ break;
+ case C2SettingResult::BAD_VALUE:
+ d->failure = SettingResult::Failure::BAD_VALUE;
+ break;
+ case C2SettingResult::CONFLICT:
+ d->failure = SettingResult::Failure::CONFLICT;
+ break;
+ case C2SettingResult::UNSUPPORTED:
+ d->failure = SettingResult::Failure::UNSUPPORTED;
+ break;
+ case C2SettingResult::INFO_BAD_VALUE:
+ d->failure = SettingResult::Failure::INFO_BAD_VALUE;
+ break;
+ case C2SettingResult::INFO_CONFLICT:
+ d->failure = SettingResult::Failure::INFO_CONFLICT;
+ break;
+ default:
+ LOG(DEBUG) << "Unrecognized C2SettingResult::Failure "
+ << "with underlying value " << underlying_value(s.failure)
+ << ".";
+ d->failure = static_cast<SettingResult::Failure>(s.failure);
+ }
+ if (!objcpy(&d->field, s.field)) {
+ LOG(ERROR) << "Invalid C2SettingResult::field.";
+ return false;
+ }
+ d->conflicts.resize(s.conflicts.size());
+ size_t i = 0;
+ for (const C2ParamFieldValues& sConflict : s.conflicts) {
+ ParamFieldValues &dConflict = d->conflicts[i++];
+ if (!objcpy(&dConflict, sConflict)) {
+ LOG(ERROR) << "Invalid C2SettingResult::conflicts["
+ << i - 1 << "].";
+ return false;
+ }
+ }
+ return true;
+}
+
+// SettingResult -> std::unique_ptr<C2SettingResult>
+bool objcpy(std::unique_ptr<C2SettingResult> *d, const SettingResult &s) {
+ *d = std::unique_ptr<C2SettingResult>(new C2SettingResult {
+ .field = C2ParamFieldValues(C2ParamFieldBuilder()) });
+ if (!*d) {
+ LOG(ERROR) << "No memory for C2SettingResult.";
+ return false;
+ }
+
+ // failure
+ switch (s.failure) {
+ case SettingResult::Failure::BAD_TYPE:
+ (*d)->failure = C2SettingResult::BAD_TYPE;
+ break;
+ case SettingResult::Failure::BAD_PORT:
+ (*d)->failure = C2SettingResult::BAD_PORT;
+ break;
+ case SettingResult::Failure::BAD_INDEX:
+ (*d)->failure = C2SettingResult::BAD_INDEX;
+ break;
+ case SettingResult::Failure::READ_ONLY:
+ (*d)->failure = C2SettingResult::READ_ONLY;
+ break;
+ case SettingResult::Failure::MISMATCH:
+ (*d)->failure = C2SettingResult::MISMATCH;
+ break;
+ case SettingResult::Failure::BAD_VALUE:
+ (*d)->failure = C2SettingResult::BAD_VALUE;
+ break;
+ case SettingResult::Failure::CONFLICT:
+ (*d)->failure = C2SettingResult::CONFLICT;
+ break;
+ case SettingResult::Failure::UNSUPPORTED:
+ (*d)->failure = C2SettingResult::UNSUPPORTED;
+ break;
+ case SettingResult::Failure::INFO_BAD_VALUE:
+ (*d)->failure = C2SettingResult::INFO_BAD_VALUE;
+ break;
+ case SettingResult::Failure::INFO_CONFLICT:
+ (*d)->failure = C2SettingResult::INFO_CONFLICT;
+ break;
+ default:
+ LOG(DEBUG) << "Unrecognized SettingResult::Failure "
+ << "with underlying value " << underlying_value(s.failure)
+ << ".";
+ (*d)->failure = static_cast<C2SettingResult::Failure>(s.failure);
+ }
+
+ // field
+ if (!objcpy(&(*d)->field, s.field)) {
+ LOG(ERROR) << "Invalid SettingResult::field.";
+ return false;
+ }
+
+ // conflicts
+ (*d)->conflicts.clear();
+ (*d)->conflicts.reserve(s.conflicts.size());
+ for (const ParamFieldValues& sConflict : s.conflicts) {
+ (*d)->conflicts.emplace_back(
+ C2ParamFieldValues{ C2ParamFieldBuilder(), nullptr });
+ if (!objcpy(&(*d)->conflicts.back(), sConflict)) {
+ LOG(ERROR) << "Invalid SettingResult::conflicts.";
+ return false;
+ }
+ }
+ return true;
+}
+
+// C2ParamDescriptor -> ParamDescriptor
+bool objcpy(ParamDescriptor *d, const C2ParamDescriptor &s) {
+ d->index = static_cast<ParamIndex>(s.index());
+ d->attrib = static_cast<hidl_bitfield<ParamDescriptor::Attrib>>(
+ _C2ParamInspector::GetAttrib(s));
+ d->name = s.name();
+ copyVector<uint32_t>(&d->dependencies, s.dependencies());
+ return true;
+}
+
+// ParamDescriptor -> C2ParamDescriptor
+bool objcpy(std::shared_ptr<C2ParamDescriptor> *d, const ParamDescriptor &s) {
+ std::vector<C2Param::Index> dDependencies;
+ dDependencies.reserve(s.dependencies.size());
+ for (const ParamIndex& sDependency : s.dependencies) {
+ dDependencies.emplace_back(static_cast<uint32_t>(sDependency));
+ }
+ *d = std::make_shared<C2ParamDescriptor>(
+ C2Param::Index(static_cast<uint32_t>(s.index)),
+ static_cast<C2ParamDescriptor::attrib_t>(s.attrib),
+ C2String(s.name.c_str()),
+ std::move(dDependencies));
+ return true;
+}
+
+// C2StructDescriptor -> StructDescriptor
+bool objcpy(StructDescriptor *d, const C2StructDescriptor &s) {
+ d->type = static_cast<ParamIndex>(s.coreIndex().coreIndex());
+ d->fields.resize(s.numFields());
+ size_t i = 0;
+ for (const auto& sField : s) {
+ FieldDescriptor& dField = d->fields[i++];
+ dField.fieldId.offset = static_cast<uint32_t>(
+ _C2ParamInspector::GetOffset(sField));
+ dField.fieldId.size = static_cast<uint32_t>(
+ _C2ParamInspector::GetSize(sField));
+ dField.type = static_cast<hidl_bitfield<FieldDescriptor::Type>>(
+ sField.type());
+ dField.extent = static_cast<uint32_t>(sField.extent());
+ dField.name = static_cast<hidl_string>(sField.name());
+ const auto& sNamedValues = sField.namedValues();
+ dField.namedValues.resize(sNamedValues.size());
+ size_t j = 0;
+ for (const auto& sNamedValue : sNamedValues) {
+ FieldDescriptor::NamedValue& dNamedValue = dField.namedValues[j++];
+ dNamedValue.name = static_cast<hidl_string>(sNamedValue.first);
+ dNamedValue.value = static_cast<PrimitiveValue>(
+ sNamedValue.second.u64);
+ }
+ }
+ return true;
+}
+
+// StructDescriptor -> C2StructDescriptor
+bool objcpy(std::unique_ptr<C2StructDescriptor> *d, const StructDescriptor &s) {
+ C2Param::CoreIndex dIndex = C2Param::CoreIndex(static_cast<uint32_t>(s.type));
+ std::vector<C2FieldDescriptor> dFields;
+ dFields.reserve(s.fields.size());
+ for (const auto &sField : s.fields) {
+ C2FieldDescriptor dField = {
+ static_cast<uint32_t>(sField.type),
+ sField.extent,
+ sField.name,
+ sField.fieldId.offset,
+ sField.fieldId.size };
+ C2FieldDescriptor::NamedValuesType namedValues;
+ namedValues.reserve(sField.namedValues.size());
+ for (const auto& sNamedValue : sField.namedValues) {
+ namedValues.emplace_back(
+ sNamedValue.name,
+ C2Value::Primitive(static_cast<uint64_t>(sNamedValue.value)));
+ }
+ _C2ParamInspector::AddNamedValues(dField, std::move(namedValues));
+ dFields.emplace_back(dField);
+ }
+ *d = std::make_unique<C2StructDescriptor>(
+ _C2ParamInspector::CreateStructDescriptor(dIndex, std::move(dFields)));
+ return true;
+}
+
+namespace /* unnamed */ {
+
+// Find or add a hidl BaseBlock object from a given C2Handle* to a list and an
+// associated map.
+// Note: The handle is not cloned.
+bool _addBaseBlock(
+ uint32_t* index,
+ const C2Handle* handle,
+ std::list<BaseBlock>* baseBlocks,
+ std::map<const void*, uint32_t>* baseBlockIndices) {
+ if (!handle) {
+ LOG(ERROR) << "addBaseBlock called on a null C2Handle.";
+ return false;
+ }
+ auto it = baseBlockIndices->find(handle);
+ if (it != baseBlockIndices->end()) {
+ *index = it->second;
+ } else {
+ *index = baseBlocks->size();
+ baseBlockIndices->emplace(handle, *index);
+ baseBlocks->emplace_back();
+
+ BaseBlock &dBaseBlock = baseBlocks->back();
+ // This does not clone the handle.
+ dBaseBlock.nativeBlock(
+ reinterpret_cast<const native_handle_t*>(handle));
+
+ }
+ return true;
+}
+
+// Find or add a hidl BaseBlock object from a given BufferPoolData to a list and
+// an associated map.
+bool _addBaseBlock(
+ uint32_t* index,
+ const std::shared_ptr<BufferPoolData> bpData,
+ BufferPoolSender* bufferPoolSender,
+ std::list<BaseBlock>* baseBlocks,
+ std::map<const void*, uint32_t>* baseBlockIndices) {
+ if (!bpData) {
+ LOG(ERROR) << "addBaseBlock called on a null BufferPoolData.";
+ return false;
+ }
+ auto it = baseBlockIndices->find(bpData.get());
+ if (it != baseBlockIndices->end()) {
+ *index = it->second;
+ } else {
+ *index = baseBlocks->size();
+ baseBlockIndices->emplace(bpData.get(), *index);
+ baseBlocks->emplace_back();
+
+ BaseBlock &dBaseBlock = baseBlocks->back();
+
+ if (bufferPoolSender) {
+ BufferStatusMessage pooledBlock;
+ ResultStatus bpStatus = bufferPoolSender->send(
+ bpData,
+ &pooledBlock);
+
+ if (bpStatus != ResultStatus::OK) {
+ LOG(ERROR) << "Failed to send buffer with BufferPool. Error: "
+ << static_cast<int32_t>(bpStatus)
+ << ".";
+ return false;
+ }
+ dBaseBlock.pooledBlock(pooledBlock);
+ }
+ }
+ return true;
+}
+
+bool addBaseBlock(
+ uint32_t* index,
+ const C2Handle* handle,
+ const std::shared_ptr<const _C2BlockPoolData>& blockPoolData,
+ BufferPoolSender* bufferPoolSender,
+ std::list<BaseBlock>* baseBlocks,
+ std::map<const void*, uint32_t>* baseBlockIndices) {
+ if (!blockPoolData) {
+ // No BufferPoolData ==> NATIVE block.
+ return _addBaseBlock(
+ index, handle,
+ baseBlocks, baseBlockIndices);
+ }
+ switch (blockPoolData->getType()) {
+ case _C2BlockPoolData::TYPE_BUFFERPOOL: {
+ // BufferPoolData
+ std::shared_ptr<BufferPoolData> bpData;
+ if (!_C2BlockFactory::GetBufferPoolData(blockPoolData, &bpData)
+ || !bpData) {
+ LOG(ERROR) << "BufferPoolData unavailable in a block.";
+ return false;
+ }
+ return _addBaseBlock(
+ index, bpData,
+ bufferPoolSender, baseBlocks, baseBlockIndices);
+ }
+ case _C2BlockPoolData::TYPE_BUFFERQUEUE:
+ uint32_t gen;
+ uint64_t bqId;
+ int32_t bqSlot;
+ // Update handle if migration happened.
+ if (_C2BlockFactory::GetBufferQueueData(
+ blockPoolData, &gen, &bqId, &bqSlot)) {
+ android::MigrateNativeCodec2GrallocHandle(
+ const_cast<native_handle_t*>(handle), gen, bqId, bqSlot);
+ }
+ return _addBaseBlock(
+ index, handle,
+ baseBlocks, baseBlockIndices);
+ default:
+ LOG(ERROR) << "Unknown C2BlockPoolData type.";
+ return false;
+ }
+}
+
+// C2Fence -> hidl_handle
+// Note: File descriptors are not duplicated. The original file descriptor must
+// not be closed before the transaction is complete.
+bool objcpy(hidl_handle* d, const C2Fence& s) {
+ d->setTo(nullptr);
+ native_handle_t* handle = _C2FenceFactory::CreateNativeHandle(s);
+ if (handle) {
+ d->setTo(handle, true /* owns */);
+// } else if (!s.ready()) {
+// // TODO: we should wait for unmarshallable fences but this may not be
+// // the best place for it. We can safely ignore here as at this time
+// // all fences used here are marshallable.
+ }
+ return true;
+}
+
+// C2ConstLinearBlock -> Block
+// Note: Native handles are not duplicated. The original handles must not be
+// closed before the transaction is complete.
+bool objcpy(Block* d, const C2ConstLinearBlock& s,
+ BufferPoolSender* bufferPoolSender,
+ std::list<BaseBlock>* baseBlocks,
+ std::map<const void*, uint32_t>* baseBlockIndices) {
+ std::shared_ptr<const _C2BlockPoolData> bpData =
+ _C2BlockFactory::GetLinearBlockPoolData(s);
+ if (!addBaseBlock(&d->index, s.handle(), bpData,
+ bufferPoolSender, baseBlocks, baseBlockIndices)) {
+ LOG(ERROR) << "Invalid block data in C2ConstLinearBlock.";
+ return false;
+ }
+
+ // Create the metadata.
+ C2Hidl_RangeInfo dRangeInfo;
+ dRangeInfo.offset = static_cast<uint32_t>(s.offset());
+ dRangeInfo.length = static_cast<uint32_t>(s.size());
+ if (!createParamsBlob(&d->meta, std::vector<C2Param*>{ &dRangeInfo })) {
+ LOG(ERROR) << "Invalid range info in C2ConstLinearBlock.";
+ return false;
+ }
+
+ // Copy the fence
+ if (!objcpy(&d->fence, s.fence())) {
+ LOG(ERROR) << "Invalid C2ConstLinearBlock::fence.";
+ return false;
+ }
+ return true;
+}
+
+// C2ConstGraphicBlock -> Block
+// Note: Native handles are not duplicated. The original handles must not be
+// closed before the transaction is complete.
+bool objcpy(Block* d, const C2ConstGraphicBlock& s,
+ BufferPoolSender* bufferPoolSender,
+ std::list<BaseBlock>* baseBlocks,
+ std::map<const void*, uint32_t>* baseBlockIndices) {
+ std::shared_ptr<const _C2BlockPoolData> bpData =
+ _C2BlockFactory::GetGraphicBlockPoolData(s);
+ if (!addBaseBlock(&d->index, s.handle(), bpData,
+ bufferPoolSender, baseBlocks, baseBlockIndices)) {
+ LOG(ERROR) << "Invalid block data in C2ConstGraphicBlock.";
+ return false;
+ }
+
+ // Create the metadata.
+ C2Hidl_RectInfo dRectInfo;
+ C2Rect sRect = s.crop();
+ dRectInfo.left = static_cast<uint32_t>(sRect.left);
+ dRectInfo.top = static_cast<uint32_t>(sRect.top);
+ dRectInfo.width = static_cast<uint32_t>(sRect.width);
+ dRectInfo.height = static_cast<uint32_t>(sRect.height);
+ if (!createParamsBlob(&d->meta, std::vector<C2Param*>{ &dRectInfo })) {
+ LOG(ERROR) << "Invalid rect info in C2ConstGraphicBlock.";
+ return false;
+ }
+
+ // Copy the fence
+ if (!objcpy(&d->fence, s.fence())) {
+ LOG(ERROR) << "Invalid C2ConstGraphicBlock::fence.";
+ return false;
+ }
+ return true;
+}
+
+// C2BufferData -> Buffer
+// This function only fills in d->blocks.
+bool objcpy(Buffer* d, const C2BufferData& s,
+ BufferPoolSender* bufferPoolSender,
+ std::list<BaseBlock>* baseBlocks,
+ std::map<const void*, uint32_t>* baseBlockIndices) {
+ d->blocks.resize(
+ s.linearBlocks().size() +
+ s.graphicBlocks().size());
+ size_t i = 0;
+ for (const C2ConstLinearBlock& linearBlock : s.linearBlocks()) {
+ Block& dBlock = d->blocks[i++];
+ if (!objcpy(
+ &dBlock, linearBlock,
+ bufferPoolSender, baseBlocks, baseBlockIndices)) {
+ LOG(ERROR) << "Invalid C2BufferData::linearBlocks. "
+ << "(Destination index = " << i - 1 << ".)";
+ return false;
+ }
+ }
+ for (const C2ConstGraphicBlock& graphicBlock : s.graphicBlocks()) {
+ Block& dBlock = d->blocks[i++];
+ if (!objcpy(
+ &dBlock, graphicBlock,
+ bufferPoolSender, baseBlocks, baseBlockIndices)) {
+ LOG(ERROR) << "Invalid C2BufferData::graphicBlocks. "
+ << "(Destination index = " << i - 1 << ".)";
+ return false;
+ }
+ }
+ return true;
+}
+
+// C2Buffer -> Buffer
+bool objcpy(Buffer* d, const C2Buffer& s,
+ BufferPoolSender* bufferPoolSender,
+ std::list<BaseBlock>* baseBlocks,
+ std::map<const void*, uint32_t>* baseBlockIndices) {
+ if (!createParamsBlob(&d->info, s.info())) {
+ LOG(ERROR) << "Invalid C2Buffer::info.";
+ return false;
+ }
+ if (!objcpy(d, s.data(), bufferPoolSender, baseBlocks, baseBlockIndices)) {
+ LOG(ERROR) << "Invalid C2Buffer::data.";
+ return false;
+ }
+ return true;
+}
+
+// C2InfoBuffer -> InfoBuffer
+bool objcpy(InfoBuffer* d, const C2InfoBuffer& s,
+ BufferPoolSender* bufferPoolSender,
+ std::list<BaseBlock>* baseBlocks,
+ std::map<const void*, uint32_t>* baseBlockIndices) {
+ d->index = static_cast<ParamIndex>(s.index());
+ Buffer& dBuffer = d->buffer;
+ if (!objcpy(&dBuffer, s.data(), bufferPoolSender, baseBlocks, baseBlockIndices)) {
+ LOG(ERROR) << "Invalid C2InfoBuffer::data";
+ return false;
+ }
+ return true;
+}
+
+// C2FrameData -> FrameData
+bool objcpy(FrameData* d, const C2FrameData& s,
+ BufferPoolSender* bufferPoolSender,
+ std::list<BaseBlock>* baseBlocks,
+ std::map<const void*, uint32_t>* baseBlockIndices) {
+ d->flags = static_cast<hidl_bitfield<FrameData::Flags>>(s.flags);
+ if (!objcpy(&d->ordinal, s.ordinal)) {
+ LOG(ERROR) << "Invalid C2FrameData::ordinal.";
+ return false;
+ }
+
+ d->buffers.resize(s.buffers.size());
+ size_t i = 0;
+ for (const std::shared_ptr<C2Buffer>& sBuffer : s.buffers) {
+ Buffer& dBuffer = d->buffers[i++];
+ if (!sBuffer) {
+ // A null (pointer to) C2Buffer corresponds to a Buffer with empty
+ // info and blocks.
+ dBuffer.info.resize(0);
+ dBuffer.blocks.resize(0);
+ continue;
+ }
+ if (!objcpy(
+ &dBuffer, *sBuffer,
+ bufferPoolSender, baseBlocks, baseBlockIndices)) {
+ LOG(ERROR) << "Invalid C2FrameData::buffers["
+ << i - 1 << "].";
+ return false;
+ }
+ }
+
+ if (!createParamsBlob(&d->configUpdate, s.configUpdate)) {
+ LOG(ERROR) << "Invalid C2FrameData::configUpdate.";
+ return false;
+ }
+
+ d->infoBuffers.resize(s.infoBuffers.size());
+ i = 0;
+ for (const C2InfoBuffer& sInfoBuffer : s.infoBuffers) {
+ InfoBuffer& dInfoBuffer = d->infoBuffers[i++];
+ if (!objcpy(&dInfoBuffer, sInfoBuffer,
+ bufferPoolSender, baseBlocks, baseBlockIndices)) {
+ LOG(ERROR) << "Invalid C2FrameData::infoBuffers["
+ << i - 1 << "].";
+ return false;
+ }
+ }
+
+ return true;
+}
+
+} // unnamed namespace
+
+// DefaultBufferPoolSender's implementation
+
+DefaultBufferPoolSender::DefaultBufferPoolSender(
+ const sp<IClientManager>& receiverManager,
+ std::chrono::steady_clock::duration refreshInterval)
+ : mReceiverManager(receiverManager),
+ mRefreshInterval(refreshInterval) {
+}
+
+void DefaultBufferPoolSender::setReceiver(
+ const sp<IClientManager>& receiverManager,
+ std::chrono::steady_clock::duration refreshInterval) {
+ std::lock_guard<std::mutex> lock(mMutex);
+ if (mReceiverManager != receiverManager) {
+ mReceiverManager = receiverManager;
+ mConnections.clear();
+ }
+ mRefreshInterval = refreshInterval;
+}
+
+ResultStatus DefaultBufferPoolSender::send(
+ const std::shared_ptr<BufferPoolData>& bpData,
+ BufferStatusMessage* bpMessage) {
+ int64_t connectionId = bpData->mConnectionId;
+ if (connectionId == 0) {
+ LOG(WARNING) << "registerSender -- invalid sender connection id (0).";
+ return ResultStatus::CRITICAL_ERROR;
+ }
+ std::lock_guard<std::mutex> lock(mMutex);
+ if (!mReceiverManager) {
+ LOG(ERROR) << "No access to receiver's BufferPool.";
+ return ResultStatus::NOT_FOUND;
+ }
+ if (!mSenderManager) {
+ mSenderManager = ClientManager::getInstance();
+ if (!mSenderManager) {
+ LOG(ERROR) << "Failed to retrieve local BufferPool ClientManager.";
+ return ResultStatus::CRITICAL_ERROR;
+ }
+ }
+
+ int64_t receiverConnectionId{0};
+ auto foundConnection = mConnections.find(connectionId);
+ bool isNewConnection = foundConnection == mConnections.end();
+ std::chrono::steady_clock::time_point now =
+ std::chrono::steady_clock::now();
+ if (isNewConnection ||
+ (now - foundConnection->second.lastSent > mRefreshInterval)) {
+ // Initialize the bufferpool connection.
+ ResultStatus rs =
+ mSenderManager->registerSender(mReceiverManager,
+ connectionId,
+ &receiverConnectionId);
+ if ((rs != ResultStatus::OK) && (rs != ResultStatus::ALREADY_EXISTS)) {
+ LOG(WARNING) << "registerSender -- returned error: "
+ << static_cast<int32_t>(rs)
+ << ".";
+ return rs;
+ } else if (receiverConnectionId == 0) {
+ LOG(WARNING) << "registerSender -- "
+ "invalid receiver connection id (0).";
+ return ResultStatus::CRITICAL_ERROR;
+ } else {
+ if (isNewConnection) {
+ foundConnection = mConnections.try_emplace(
+ connectionId, receiverConnectionId, now).first;
+ } else {
+ foundConnection->second.receiverConnectionId = receiverConnectionId;
+ }
+ }
+ } else {
+ receiverConnectionId = foundConnection->second.receiverConnectionId;
+ }
+
+ uint64_t transactionId;
+ int64_t timestampUs;
+ ResultStatus rs = mSenderManager->postSend(
+ receiverConnectionId, bpData, &transactionId, ×tampUs);
+ if (rs != ResultStatus::OK) {
+ LOG(ERROR) << "ClientManager::postSend -- returned error: "
+ << static_cast<int32_t>(rs)
+ << ".";
+ mConnections.erase(foundConnection);
+ return rs;
+ }
+ if (!bpMessage) {
+ LOG(ERROR) << "Null output parameter for BufferStatusMessage.";
+ mConnections.erase(foundConnection);
+ return ResultStatus::CRITICAL_ERROR;
+ }
+ bpMessage->connectionId = receiverConnectionId;
+ bpMessage->bufferId = bpData->mId;
+ bpMessage->transactionId = transactionId;
+ bpMessage->timestampUs = timestampUs;
+ foundConnection->second.lastSent = now;
+ return rs;
+}
+
+// std::list<std::unique_ptr<C2Work>> -> WorkBundle
+bool objcpy(
+ WorkBundle* d,
+ const std::list<std::unique_ptr<C2Work>>& s,
+ BufferPoolSender* bufferPoolSender) {
+ // baseBlocks holds a list of BaseBlock objects that Blocks can refer to.
+ std::list<BaseBlock> baseBlocks;
+
+ // baseBlockIndices maps a raw pointer to native_handle_t or BufferPoolData
+ // inside baseBlocks to the corresponding index into baseBlocks. The keys
+ // (pointers) are used to identify blocks that have the same "base block" in
+ // s, a list of C2Work objects. Because baseBlocks will be copied into a
+ // hidl_vec eventually, the values of baseBlockIndices are zero-based
+ // integer indices instead of list iterators.
+ //
+ // Note that the pointers can be raw because baseBlockIndices has a shorter
+ // lifespan than all of base blocks.
+ std::map<const void*, uint32_t> baseBlockIndices;
+
+ d->works.resize(s.size());
+ size_t i = 0;
+ for (const std::unique_ptr<C2Work>& sWork : s) {
+ Work &dWork = d->works[i++];
+ if (!sWork) {
+ LOG(WARNING) << "Null C2Work encountered.";
+ continue;
+ }
+
+ // chain info is not in use currently.
+
+ // input
+ if (!objcpy(&dWork.input, sWork->input,
+ bufferPoolSender, &baseBlocks, &baseBlockIndices)) {
+ LOG(ERROR) << "Invalid C2Work::input.";
+ return false;
+ }
+
+ // worklets
+ if (sWork->worklets.size() == 0) {
+ LOG(DEBUG) << "Work with no worklets.";
+ } else {
+ // Parcel the worklets.
+ hidl_vec<Worklet> &dWorklets = dWork.worklets;
+ dWorklets.resize(sWork->worklets.size());
+ size_t j = 0;
+ for (const std::unique_ptr<C2Worklet>& sWorklet : sWork->worklets)
+ {
+ if (!sWorklet) {
+ LOG(WARNING) << "Null C2Work::worklets["
+ << j << "].";
+ continue;
+ }
+ Worklet &dWorklet = dWorklets[j++];
+
+ // component id
+ dWorklet.componentId = static_cast<uint32_t>(
+ sWorklet->component);
+
+ // tunings
+ if (!createParamsBlob(&dWorklet.tunings, sWorklet->tunings)) {
+ LOG(ERROR) << "Invalid C2Work::worklets["
+ << j - 1 << "]->tunings.";
+ return false;
+ }
+
+ // failures
+ dWorklet.failures.resize(sWorklet->failures.size());
+ size_t k = 0;
+ for (const std::unique_ptr<C2SettingResult>& sFailure :
+ sWorklet->failures) {
+ if (!sFailure) {
+ LOG(WARNING) << "Null C2Work::worklets["
+ << j - 1 << "]->failures["
+ << k << "].";
+ continue;
+ }
+ if (!objcpy(&dWorklet.failures[k++], *sFailure)) {
+ LOG(ERROR) << "Invalid C2Work::worklets["
+ << j - 1 << "]->failures["
+ << k - 1 << "].";
+ return false;
+ }
+ }
+
+ // output
+ if (!objcpy(&dWorklet.output, sWorklet->output,
+ bufferPoolSender, &baseBlocks, &baseBlockIndices)) {
+ LOG(ERROR) << "Invalid C2Work::worklets["
+ << j - 1 << "]->output.";
+ return false;
+ }
+ }
+ }
+
+ // worklets processed
+ dWork.workletsProcessed = sWork->workletsProcessed;
+
+ // result
+ dWork.result = static_cast<Status>(sWork->result);
+ }
+
+ // Copy std::list<BaseBlock> to hidl_vec<BaseBlock>.
+ {
+ d->baseBlocks.resize(baseBlocks.size());
+ size_t i = 0;
+ for (const BaseBlock& baseBlock : baseBlocks) {
+ d->baseBlocks[i++] = baseBlock;
+ }
+ }
+
+ return true;
+}
+
+namespace /* unnamed */ {
+
+struct C2BaseBlock {
+ enum type_t {
+ LINEAR,
+ GRAPHIC,
+ };
+ type_t type;
+ std::shared_ptr<C2LinearBlock> linear;
+ std::shared_ptr<C2GraphicBlock> graphic;
+};
+
+// hidl_handle -> C2Fence
+// Note: File descriptors are not duplicated. The original file descriptor must
+// not be closed before the transaction is complete.
+bool objcpy(C2Fence* d, const hidl_handle& s) {
+ const native_handle_t* handle = s.getNativeHandle();
+ *d = _C2FenceFactory::CreateFromNativeHandle(handle);
+ return true;
+}
+
+// C2LinearBlock, vector<C2Param*>, C2Fence -> C2Buffer
+bool createLinearBuffer(
+ std::shared_ptr<C2Buffer>* buffer,
+ const std::shared_ptr<C2LinearBlock>& block,
+ const std::vector<C2Param*>& meta,
+ const C2Fence& fence) {
+ // Check the block meta. It should have exactly 1 C2Info:
+ // C2Hidl_RangeInfo.
+ if ((meta.size() != 1) || !meta[0]) {
+ LOG(ERROR) << "Invalid C2LinearBlock::meta.";
+ return false;
+ }
+ if (meta[0]->size() != sizeof(C2Hidl_RangeInfo)) {
+ LOG(ERROR) << "Invalid range info in C2LinearBlock.";
+ return false;
+ }
+ C2Hidl_RangeInfo *rangeInfo =
+ reinterpret_cast<C2Hidl_RangeInfo*>(meta[0]);
+
+ // Create C2Buffer from C2LinearBlock.
+ *buffer = C2Buffer::CreateLinearBuffer(block->share(
+ rangeInfo->offset, rangeInfo->length,
+ fence));
+ if (!(*buffer)) {
+ LOG(ERROR) << "CreateLinearBuffer failed.";
+ return false;
+ }
+ return true;
+}
+
+// C2GraphicBlock, vector<C2Param*>, C2Fence -> C2Buffer
+bool createGraphicBuffer(
+ std::shared_ptr<C2Buffer>* buffer,
+ const std::shared_ptr<C2GraphicBlock>& block,
+ const std::vector<C2Param*>& meta,
+ const C2Fence& fence) {
+ // Check the block meta. It should have exactly 1 C2Info:
+ // C2Hidl_RectInfo.
+ if ((meta.size() != 1) || !meta[0]) {
+ LOG(ERROR) << "Invalid C2GraphicBlock::meta.";
+ return false;
+ }
+ if (meta[0]->size() != sizeof(C2Hidl_RectInfo)) {
+ LOG(ERROR) << "Invalid rect info in C2GraphicBlock.";
+ return false;
+ }
+ C2Hidl_RectInfo *rectInfo =
+ reinterpret_cast<C2Hidl_RectInfo*>(meta[0]);
+
+ // Create C2Buffer from C2GraphicBlock.
+ *buffer = C2Buffer::CreateGraphicBuffer(block->share(
+ C2Rect(rectInfo->width, rectInfo->height).
+ at(rectInfo->left, rectInfo->top),
+ fence));
+ if (!(*buffer)) {
+ LOG(ERROR) << "CreateGraphicBuffer failed.";
+ return false;
+ }
+ return true;
+}
+
+// Buffer -> C2Buffer
+// Note: The native handles will be cloned.
+bool objcpy(std::shared_ptr<C2Buffer>* d, const Buffer& s,
+ const std::vector<C2BaseBlock>& baseBlocks) {
+ *d = nullptr;
+
+ // Currently, a non-null C2Buffer must contain exactly 1 block.
+ if (s.blocks.size() == 0) {
+ return true;
+ } else if (s.blocks.size() != 1) {
+ LOG(ERROR) << "Invalid Buffer: "
+ "Currently, a C2Buffer must contain exactly 1 block.";
+ return false;
+ }
+
+ const Block &sBlock = s.blocks[0];
+ if (sBlock.index >= baseBlocks.size()) {
+ LOG(ERROR) << "Invalid Buffer::blocks[0].index: "
+ "Array index out of range.";
+ return false;
+ }
+ const C2BaseBlock &baseBlock = baseBlocks[sBlock.index];
+
+ // Parse meta.
+ std::vector<C2Param*> sBlockMeta;
+ if (!parseParamsBlob(&sBlockMeta, sBlock.meta)) {
+ LOG(ERROR) << "Invalid Buffer::blocks[0].meta.";
+ return false;
+ }
+
+ // Copy fence.
+ C2Fence dFence;
+ if (!objcpy(&dFence, sBlock.fence)) {
+ LOG(ERROR) << "Invalid Buffer::blocks[0].fence.";
+ return false;
+ }
+
+ // Construct a block.
+ switch (baseBlock.type) {
+ case C2BaseBlock::LINEAR:
+ if (!createLinearBuffer(d, baseBlock.linear, sBlockMeta, dFence)) {
+ LOG(ERROR) << "Invalid C2BaseBlock::linear.";
+ return false;
+ }
+ break;
+ case C2BaseBlock::GRAPHIC:
+ if (!createGraphicBuffer(d, baseBlock.graphic, sBlockMeta, dFence)) {
+ LOG(ERROR) << "Invalid C2BaseBlock::graphic.";
+ return false;
+ }
+ break;
+ default:
+ LOG(ERROR) << "Invalid C2BaseBlock::type.";
+ return false;
+ }
+
+ // Parse info
+ std::vector<C2Param*> params;
+ if (!parseParamsBlob(¶ms, s.info)) {
+ LOG(ERROR) << "Invalid Buffer::info.";
+ return false;
+ }
+ for (C2Param* param : params) {
+ if (param == nullptr) {
+ LOG(ERROR) << "Null param in Buffer::info.";
+ return false;
+ }
+ std::shared_ptr<C2Param> c2param{
+ C2Param::Copy(*param).release()};
+ if (!c2param) {
+ LOG(ERROR) << "Invalid param in Buffer::info.";
+ return false;
+ }
+ c2_status_t status =
+ (*d)->setInfo(std::static_pointer_cast<C2Info>(c2param));
+ if (status != C2_OK) {
+ LOG(ERROR) << "C2Buffer::setInfo failed.";
+ return false;
+ }
+ }
+
+ return true;
+}
+
+// InfoBuffer -> C2InfoBuffer
+bool objcpy(std::vector<C2InfoBuffer> *d, const InfoBuffer& s,
+ const std::vector<C2BaseBlock>& baseBlocks) {
+
+ // Currently, a non-null C2InfoBufer must contain exactly 1 block.
+ if (s.buffer.blocks.size() == 0) {
+ return true;
+ } else if (s.buffer.blocks.size() != 1) {
+ LOG(ERROR) << "Invalid InfoBuffer::Buffer "
+ "Currently, a C2InfoBuffer must contain exactly 1 block.";
+ return false;
+ }
+
+ const Block &sBlock = s.buffer.blocks[0];
+ if (sBlock.index >= baseBlocks.size()) {
+ LOG(ERROR) << "Invalid InfoBuffer::Buffer::blocks[0].index: "
+ "Array index out of range.";
+ return false;
+ }
+ const C2BaseBlock &baseBlock = baseBlocks[sBlock.index];
+
+ // Parse meta.
+ std::vector<C2Param*> sBlockMeta;
+ if (!parseParamsBlob(&sBlockMeta, sBlock.meta)) {
+ LOG(ERROR) << "Invalid InfoBuffer::Buffer::blocks[0].meta.";
+ return false;
+ }
+
+ // Copy fence.
+ C2Fence dFence;
+ if (!objcpy(&dFence, sBlock.fence)) {
+ LOG(ERROR) << "Invalid InfoBuffer::Buffer::blocks[0].fence.";
+ return false;
+ }
+
+ // Construct a block.
+ switch (baseBlock.type) {
+ case C2BaseBlock::LINEAR:
+ if (sBlockMeta.size() == 1 && sBlockMeta[0] != nullptr &&
+ sBlockMeta[0]->size() == sizeof(C2Hidl_RangeInfo)) {
+ C2Hidl_RangeInfo *rangeInfo =
+ reinterpret_cast<C2Hidl_RangeInfo*>(sBlockMeta[0]);
+ d->emplace_back(C2InfoBuffer::CreateLinearBuffer(
+ s.index,
+ baseBlock.linear->share(
+ rangeInfo->offset, rangeInfo->length, dFence)));
+ return true;
+ }
+ LOG(ERROR) << "Invalid Meta for C2BaseBlock::Linear InfoBuffer.";
+ break;
+ case C2BaseBlock::GRAPHIC:
+ // It's not used now
+ LOG(ERROR) << "Non-Used C2BaseBlock::type for InfoBuffer.";
+ break;
+ default:
+ LOG(ERROR) << "Invalid C2BaseBlock::type for InfoBuffer.";
+ break;
+ }
+
+ return false;
+}
+
+// FrameData -> C2FrameData
+bool objcpy(C2FrameData* d, const FrameData& s,
+ const std::vector<C2BaseBlock>& baseBlocks) {
+ d->flags = static_cast<C2FrameData::flags_t>(s.flags);
+ if (!objcpy(&d->ordinal, s.ordinal)) {
+ LOG(ERROR) << "Invalid FrameData::ordinal.";
+ return false;
+ }
+ d->buffers.clear();
+ d->buffers.reserve(s.buffers.size());
+ for (const Buffer& sBuffer : s.buffers) {
+ std::shared_ptr<C2Buffer> dBuffer;
+ if (!objcpy(&dBuffer, sBuffer, baseBlocks)) {
+ LOG(ERROR) << "Invalid FrameData::buffers.";
+ return false;
+ }
+ d->buffers.emplace_back(dBuffer);
+ }
+
+ std::vector<C2Param*> params;
+ if (!parseParamsBlob(¶ms, s.configUpdate)) {
+ LOG(ERROR) << "Invalid FrameData::configUpdate.";
+ return false;
+ }
+ d->configUpdate.clear();
+ for (C2Param* param : params) {
+ d->configUpdate.emplace_back(C2Param::Copy(*param));
+ if (!d->configUpdate.back()) {
+ LOG(ERROR) << "Unexpected error while parsing "
+ "FrameData::configUpdate.";
+ return false;
+ }
+ }
+
+ d->infoBuffers.clear();
+ if (s.infoBuffers.size() == 0) {
+ // InfoBuffer is optional
+ return true;
+ }
+ d->infoBuffers.reserve(s.infoBuffers.size());
+ for (const InfoBuffer &sInfoBuffer: s.infoBuffers) {
+ if (!objcpy(&(d->infoBuffers), sInfoBuffer, baseBlocks)) {
+ LOG(ERROR) << "Invalid Framedata::infoBuffers.";
+ return false;
+ }
+ }
+ return true;
+}
+
+// BaseBlock -> C2BaseBlock
+bool objcpy(C2BaseBlock* d, const BaseBlock& s) {
+ switch (s.getDiscriminator()) {
+ case BaseBlock::hidl_discriminator::nativeBlock: {
+ if (s.nativeBlock() == nullptr) {
+ LOG(ERROR) << "Null BaseBlock::nativeBlock handle";
+ return false;
+ }
+ native_handle_t* sHandle =
+ native_handle_clone(s.nativeBlock());
+ if (sHandle == nullptr) {
+ LOG(ERROR) << "Null BaseBlock::nativeBlock.";
+ return false;
+ }
+ const C2Handle *sC2Handle =
+ reinterpret_cast<const C2Handle*>(sHandle);
+
+ d->linear = _C2BlockFactory::CreateLinearBlock(sC2Handle);
+ if (d->linear) {
+ d->type = C2BaseBlock::LINEAR;
+ return true;
+ }
+
+ d->graphic = _C2BlockFactory::CreateGraphicBlock(sC2Handle);
+ if (d->graphic) {
+ d->type = C2BaseBlock::GRAPHIC;
+ return true;
+ }
+
+ LOG(ERROR) << "Unknown handle type in BaseBlock::nativeBlock.";
+ if (sHandle) {
+ native_handle_close(sHandle);
+ native_handle_delete(sHandle);
+ }
+ return false;
+ }
+ case BaseBlock::hidl_discriminator::pooledBlock: {
+ const BufferStatusMessage &bpMessage =
+ s.pooledBlock();
+ sp<ClientManager> bp = ClientManager::getInstance();
+ std::shared_ptr<BufferPoolData> bpData;
+ native_handle_t *cHandle;
+ ResultStatus bpStatus = bp->receive(
+ bpMessage.connectionId,
+ bpMessage.transactionId,
+ bpMessage.bufferId,
+ bpMessage.timestampUs,
+ &cHandle,
+ &bpData);
+ if (bpStatus != ResultStatus::OK) {
+ LOG(ERROR) << "Failed to receive buffer from bufferpool -- "
+ << "resultStatus = " << underlying_value(bpStatus)
+ << ".";
+ return false;
+ } else if (!bpData) {
+ LOG(ERROR) << "No data in bufferpool transaction.";
+ return false;
+ }
+
+ d->linear = _C2BlockFactory::CreateLinearBlock(cHandle, bpData);
+ if (d->linear) {
+ d->type = C2BaseBlock::LINEAR;
+ return true;
+ }
+
+ d->graphic = _C2BlockFactory::CreateGraphicBlock(cHandle, bpData);
+ if (d->graphic) {
+ d->type = C2BaseBlock::GRAPHIC;
+ return true;
+ }
+ if (cHandle) {
+ // Though we got cloned handle, creating block failed.
+ native_handle_close(cHandle);
+ native_handle_delete(cHandle);
+ }
+
+ LOG(ERROR) << "Unknown handle type in BaseBlock::pooledBlock.";
+ return false;
+ }
+ default:
+ LOG(ERROR) << "Unrecognized BaseBlock's discriminator with "
+ << "underlying value "
+ << underlying_value(s.getDiscriminator()) << ".";
+ return false;
+ }
+}
+
+} // unnamed namespace
+
+// WorkBundle -> std::list<std::unique_ptr<C2Work>>
+bool objcpy(std::list<std::unique_ptr<C2Work>>* d, const WorkBundle& s) {
+ // Convert BaseBlocks to C2BaseBlocks.
+ std::vector<C2BaseBlock> dBaseBlocks(s.baseBlocks.size());
+ for (size_t i = 0; i < s.baseBlocks.size(); ++i) {
+ if (!objcpy(&dBaseBlocks[i], s.baseBlocks[i])) {
+ LOG(ERROR) << "Invalid WorkBundle::baseBlocks["
+ << i << "].";
+ return false;
+ }
+ }
+
+ d->clear();
+ for (const Work& sWork : s.works) {
+ d->emplace_back(std::make_unique<C2Work>());
+ C2Work& dWork = *d->back();
+
+ // chain info is not in use currently.
+
+ // input
+ if (!objcpy(&dWork.input, sWork.input, dBaseBlocks)) {
+ LOG(ERROR) << "Invalid Work::input.";
+ return false;
+ }
+
+ // worklet(s)
+ dWork.worklets.clear();
+ for (const Worklet& sWorklet : sWork.worklets) {
+ std::unique_ptr<C2Worklet> dWorklet = std::make_unique<C2Worklet>();
+
+ // component id
+ dWorklet->component = static_cast<c2_node_id_t>(
+ sWorklet.componentId);
+
+ // tunings
+ if (!copyParamsFromBlob(&dWorklet->tunings, sWorklet.tunings)) {
+ LOG(ERROR) << "Invalid Worklet::tunings";
+ return false;
+ }
+
+ // failures
+ dWorklet->failures.clear();
+ dWorklet->failures.reserve(sWorklet.failures.size());
+ for (const SettingResult& sFailure : sWorklet.failures) {
+ std::unique_ptr<C2SettingResult> dFailure;
+ if (!objcpy(&dFailure, sFailure)) {
+ LOG(ERROR) << "Invalid Worklet::failures.";
+ return false;
+ }
+ dWorklet->failures.emplace_back(std::move(dFailure));
+ }
+
+ // output
+ if (!objcpy(&dWorklet->output, sWorklet.output, dBaseBlocks)) {
+ LOG(ERROR) << "Invalid Worklet::output.";
+ return false;
+ }
+
+ dWork.worklets.emplace_back(std::move(dWorklet));
+ }
+
+ // workletsProcessed
+ dWork.workletsProcessed = sWork.workletsProcessed;
+
+ // result
+ dWork.result = static_cast<c2_status_t>(sWork.result);
+ }
+
+ return true;
+}
+
+constexpr size_t PARAMS_ALIGNMENT = 8; // 64-bit alignment
+static_assert(PARAMS_ALIGNMENT % alignof(C2Param) == 0, "C2Param alignment mismatch");
+static_assert(PARAMS_ALIGNMENT % alignof(C2Info) == 0, "C2Param alignment mismatch");
+static_assert(PARAMS_ALIGNMENT % alignof(C2Tuning) == 0, "C2Param alignment mismatch");
+
+// Params -> std::vector<C2Param*>
+bool parseParamsBlob(std::vector<C2Param*> *params, const hidl_vec<uint8_t> &blob) {
+ // assuming blob is const here
+ size_t size = blob.size();
+ size_t ix = 0;
+ size_t old_ix = 0;
+ const uint8_t *data = blob.data();
+ C2Param *p = nullptr;
+
+ do {
+ p = C2ParamUtils::ParseFirst(data + ix, size - ix);
+ if (p) {
+ params->emplace_back(p);
+ old_ix = ix;
+ ix += p->size();
+ ix = align(ix, PARAMS_ALIGNMENT);
+ if (ix <= old_ix || ix > size) {
+ android_errorWriteLog(0x534e4554, "238083570");
+ break;
+ }
+ }
+ } while (p);
+
+ if (ix != size) {
+ LOG(ERROR) << "parseParamsBlob -- inconsistent sizes.";
+ return false;
+ }
+ return true;
+}
+
+namespace /* unnamed */ {
+
+/**
+ * Concatenates a list of C2Params into a params blob. T is a container type
+ * whose member type is compatible with C2Param*.
+ *
+ * \param[out] blob target blob
+ * \param[in] params parameters to concatenate
+ * \retval C2_OK if the blob was successfully created
+ * \retval C2_BAD_VALUE if the blob was not successful created (this only
+ * happens if the parameters were not const)
+ */
+template <typename T>
+bool _createParamsBlob(hidl_vec<uint8_t> *blob, const T ¶ms) {
+ // assuming the parameter values are const
+ size_t size = 0;
+ for (const auto &p : params) {
+ if (!p) {
+ continue;
+ }
+ size += p->size();
+ size = align(size, PARAMS_ALIGNMENT);
+ }
+ blob->resize(size);
+ size_t ix = 0;
+ for (const auto &p : params) {
+ if (!p) {
+ continue;
+ }
+ // NEVER overwrite even if param values (e.g. size) changed
+ size_t paramSize = std::min(p->size(), size - ix);
+ std::copy(
+ reinterpret_cast<const uint8_t*>(&*p),
+ reinterpret_cast<const uint8_t*>(&*p) + paramSize,
+ &(*blob)[ix]);
+ ix += paramSize;
+ ix = align(ix, PARAMS_ALIGNMENT);
+ }
+ blob->resize(ix);
+ if (ix != size) {
+ LOG(ERROR) << "createParamsBlob -- inconsistent sizes.";
+ return false;
+ }
+ return true;
+}
+
+/**
+ * Parses a params blob and create a vector of new T objects that contain copies
+ * of the params in the blob. T is C2Param or its compatible derived class.
+ *
+ * \param[out] params the resulting vector
+ * \param[in] blob parameter blob to parse
+ * \retval C2_OK if the full blob was parsed and params was constructed
+ * \retval C2_BAD_VALUE otherwise
+ */
+template <typename T>
+bool _copyParamsFromBlob(
+ std::vector<std::unique_ptr<T>>* params,
+ Params blob) {
+
+ std::vector<C2Param*> paramPointers;
+ if (!parseParamsBlob(¶mPointers, blob)) {
+ LOG(ERROR) << "copyParamsFromBlob -- failed to parse.";
+ return false;
+ }
+
+ params->resize(paramPointers.size());
+ size_t i = 0;
+ for (C2Param* const& paramPointer : paramPointers) {
+ if (!paramPointer) {
+ LOG(ERROR) << "copyParamsFromBlob -- null paramPointer.";
+ return false;
+ }
+ (*params)[i++].reset(reinterpret_cast<T*>(
+ C2Param::Copy(*paramPointer).release()));
+ }
+ return true;
+}
+
+} // unnamed namespace
+
+// std::vector<const C2Param*> -> Params
+bool createParamsBlob(
+ hidl_vec<uint8_t> *blob,
+ const std::vector<const C2Param*> ¶ms) {
+ return _createParamsBlob(blob, params);
+}
+
+// std::vector<C2Param*> -> Params
+bool createParamsBlob(
+ hidl_vec<uint8_t> *blob,
+ const std::vector<C2Param*> ¶ms) {
+ return _createParamsBlob(blob, params);
+}
+
+// std::vector<std::unique_ptr<C2Param>> -> Params
+bool createParamsBlob(
+ hidl_vec<uint8_t> *blob,
+ const std::vector<std::unique_ptr<C2Param>> ¶ms) {
+ return _createParamsBlob(blob, params);
+}
+
+// std::vector<std::unique_ptr<C2Tuning>> -> Params
+bool createParamsBlob(
+ hidl_vec<uint8_t> *blob,
+ const std::vector<std::unique_ptr<C2Tuning>> ¶ms) {
+ return _createParamsBlob(blob, params);
+}
+
+// std::vector<std::shared_ptr<const C2Info>> -> Params
+bool createParamsBlob(
+ hidl_vec<uint8_t> *blob,
+ const std::vector<std::shared_ptr<const C2Info>> ¶ms) {
+ return _createParamsBlob(blob, params);
+}
+
+// Params -> std::vector<std::unique_ptr<C2Param>>
+bool copyParamsFromBlob(
+ std::vector<std::unique_ptr<C2Param>>* params,
+ Params blob) {
+ return _copyParamsFromBlob(params, blob);
+}
+
+// Params -> std::vector<std::unique_ptr<C2Tuning>>
+bool copyParamsFromBlob(
+ std::vector<std::unique_ptr<C2Tuning>>* params,
+ Params blob) {
+ return _copyParamsFromBlob(params, blob);
+}
+
+// Params -> update std::vector<std::unique_ptr<C2Param>>
+bool updateParamsFromBlob(
+ const std::vector<C2Param*>& params,
+ const Params& blob) {
+ std::unordered_map<uint32_t, C2Param*> index2param;
+ for (C2Param* const& param : params) {
+ if (!param) {
+ LOG(ERROR) << "updateParamsFromBlob -- null output param.";
+ return false;
+ }
+ if (index2param.find(param->index()) == index2param.end()) {
+ index2param.emplace(param->index(), param);
+ }
+ }
+
+ std::vector<C2Param*> paramPointers;
+ if (!parseParamsBlob(¶mPointers, blob)) {
+ LOG(ERROR) << "updateParamsFromBlob -- failed to parse.";
+ return false;
+ }
+
+ for (C2Param* const& paramPointer : paramPointers) {
+ if (!paramPointer) {
+ LOG(ERROR) << "updateParamsFromBlob -- null input param.";
+ return false;
+ }
+ decltype(index2param)::iterator i = index2param.find(
+ paramPointer->index());
+ if (i == index2param.end()) {
+ LOG(DEBUG) << "updateParamsFromBlob -- index "
+ << paramPointer->index() << " not found. Skipping...";
+ continue;
+ }
+ if (!i->second->updateFrom(*paramPointer)) {
+ LOG(ERROR) << "updateParamsFromBlob -- size mismatch: "
+ << params.size() << " vs " << paramPointer->size()
+ << " (index = " << i->first << ").";
+ return false;
+ }
+ }
+ return true;
+}
+
+// Convert BufferPool ResultStatus to c2_status_t.
+c2_status_t toC2Status(ResultStatus rs) {
+ switch (rs) {
+ case ResultStatus::OK:
+ return C2_OK;
+ case ResultStatus::NO_MEMORY:
+ return C2_NO_MEMORY;
+ case ResultStatus::ALREADY_EXISTS:
+ return C2_DUPLICATE;
+ case ResultStatus::NOT_FOUND:
+ return C2_NOT_FOUND;
+ case ResultStatus::CRITICAL_ERROR:
+ return C2_CORRUPTED;
+ default:
+ LOG(WARNING) << "Unrecognized BufferPool ResultStatus: "
+ << static_cast<int32_t>(rs) << ".";
+ return C2_CORRUPTED;
+ }
+}
+
+namespace /* unnamed */ {
+
+template <typename BlockProcessor>
+void forEachBlock(C2FrameData& frameData,
+ BlockProcessor process) {
+ for (const std::shared_ptr<C2Buffer>& buffer : frameData.buffers) {
+ if (buffer) {
+ for (const C2ConstGraphicBlock& block :
+ buffer->data().graphicBlocks()) {
+ process(block);
+ }
+ }
+ }
+}
+
+template <typename BlockProcessor>
+void forEachBlock(const std::list<std::unique_ptr<C2Work>>& workList,
+ BlockProcessor process,
+ bool processInput, bool processOutput) {
+ for (const std::unique_ptr<C2Work>& work : workList) {
+ if (!work) {
+ continue;
+ }
+ if (processInput) {
+ forEachBlock(work->input, process);
+ }
+ if (processOutput) {
+ for (const std::unique_ptr<C2Worklet>& worklet : work->worklets) {
+ if (worklet) {
+ forEachBlock(worklet->output,
+ process);
+ }
+ }
+ }
+ }
+}
+
+} // unnamed namespace
+
+bool beginTransferBufferQueueBlock(const C2ConstGraphicBlock& block) {
+ std::shared_ptr<_C2BlockPoolData> data =
+ _C2BlockFactory::GetGraphicBlockPoolData(block);
+ if (data && _C2BlockFactory::GetBufferQueueData(data)) {
+ _C2BlockFactory::BeginTransferBlockToClient(data);
+ return true;
+ }
+ return false;
+}
+
+void beginTransferBufferQueueBlocks(
+ const std::list<std::unique_ptr<C2Work>>& workList,
+ bool processInput, bool processOutput) {
+ forEachBlock(workList, beginTransferBufferQueueBlock,
+ processInput, processOutput);
+}
+
+bool endTransferBufferQueueBlock(
+ const C2ConstGraphicBlock& block,
+ bool transfer) {
+ std::shared_ptr<_C2BlockPoolData> data =
+ _C2BlockFactory::GetGraphicBlockPoolData(block);
+ if (data && _C2BlockFactory::GetBufferQueueData(data)) {
+ _C2BlockFactory::EndTransferBlockToClient(data, transfer);
+ return true;
+ }
+ return false;
+}
+
+void endTransferBufferQueueBlocks(
+ const std::list<std::unique_ptr<C2Work>>& workList,
+ bool transfer,
+ bool processInput, bool processOutput) {
+ forEachBlock(workList,
+ std::bind(endTransferBufferQueueBlock,
+ std::placeholders::_1, transfer),
+ processInput, processOutput);
+}
+
+bool displayBufferQueueBlock(const C2ConstGraphicBlock& block) {
+ std::shared_ptr<_C2BlockPoolData> data =
+ _C2BlockFactory::GetGraphicBlockPoolData(block);
+ if (data && _C2BlockFactory::GetBufferQueueData(data)) {
+ _C2BlockFactory::DisplayBlockToBufferQueue(data);
+ return true;
+ }
+ return false;
+}
+
+} // namespace utils
+} // namespace V1_0
+} // namespace c2
+} // namespace media
+} // namespace hardware
+} // namespace android
+