Move Codec2-related code from hardware/google/av
Test: None
Bug: 112362730
Change-Id: Ie2f8ff431d65c40333f267ab9877d47089adeea4
diff --git a/media/codec2/tests/C2SampleComponent_test.cpp b/media/codec2/tests/C2SampleComponent_test.cpp
new file mode 100644
index 0000000..cd354ad
--- /dev/null
+++ b/media/codec2/tests/C2SampleComponent_test.cpp
@@ -0,0 +1,432 @@
+/*
+ * Copyright 2014 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 "C2SampleComponent_test"
+
+#include <gtest/gtest.h>
+
+#define __C2_GENERATE_GLOBAL_VARS__
+#include <C2Component.h>
+#include <C2Config.h>
+#include <C2Debug.h>
+#include <C2Enum.h>
+
+#include <unordered_map>
+
+class C2SampleComponentTest : public ::testing::Test {
+};
+
+void PrintTo(const C2FieldDescriptor &fd, ::std::ostream *os) {
+ using FD=C2FieldDescriptor;
+ switch (fd.type()) {
+ case FD::INT32: *os << "i32"; break;
+ case FD::INT64: *os << "i64"; break;
+ case FD::UINT32: *os << "u32"; break;
+ case FD::UINT64: *os << "u64"; break;
+ case FD::FLOAT: *os << "float"; break;
+ case FD::STRING: *os << "char"; break;
+ case FD::BLOB: *os << "u8"; break;
+ default:
+ if (fd.type() & FD::STRUCT_FLAG) {
+ *os << "struct-" << (fd.type() & ~FD::STRUCT_FLAG);
+ } else {
+ *os << "type-" << fd.type();
+ }
+ }
+ *os << " " << fd.name();
+ if (fd.extent() > 1) {
+ *os << "[" << fd.extent() << "]";
+ } else if (fd.extent() == 0) {
+ *os << "[]";
+ }
+ *os << " (" << fd._mFieldId << "*" << fd.extent() << ")";
+}
+
+C2ENUM(
+ MetadataType, int32_t,
+ kInvalid = -1,
+ kNone = 0,
+ kGralloc,
+ kNativeHandle,
+ kANativeWindow,
+ kCamera,
+)
+
+enum {
+ kParamIndexVideoConfig = 0x1234,
+};
+
+struct C2VideoConfigStruct {
+ int32_t width;
+ uint32_t height;
+ MetadataType metadataType;
+ int32_t supportedFormats[];
+
+ C2VideoConfigStruct() {}
+
+ DEFINE_AND_DESCRIBE_FLEX_C2STRUCT(VideoConfig, supportedFormats)
+ C2FIELD(width, "width")
+ C2FIELD(height, "height")
+ C2FIELD(metadataType, "metadata-type")
+ C2FIELD(supportedFormats, "formats")
+};
+
+typedef C2PortParam<C2Tuning, C2VideoConfigStruct> C2VideoConfigPortTuning;
+
+class MyComponentInstance : public C2ComponentInterface {
+public:
+ virtual C2String getName() const override {
+ /// \todo this seems too specific
+ return "sample.interface";
+ };
+
+ virtual c2_node_id_t getId() const override {
+ /// \todo how are these shared?
+ return 0;
+ }
+
+ virtual c2_status_t config_vb(
+ const std::vector<C2Param*> ¶ms,
+ c2_blocking_t mayBlock,
+ std::vector<std::unique_ptr<C2SettingResult>>* const failures) override {
+ (void)params;
+ (void)failures;
+ (void)mayBlock;
+ return C2_OMITTED;
+ }
+
+ virtual c2_status_t createTunnel_sm(c2_node_id_t targetComponent) override {
+ (void)targetComponent;
+ return C2_OMITTED;
+ }
+
+ virtual c2_status_t query_vb(
+ const std::vector<C2Param*> &stackParams,
+ const std::vector<C2Param::Index> &heapParamIndices,
+ c2_blocking_t mayBlock,
+ std::vector<std::unique_ptr<C2Param>>* const heapParams) const override {
+ for (C2Param* const param : stackParams) {
+ (void)mayBlock;
+ if (!*param) { // param is already invalid - remember it
+ continue;
+ }
+
+ // note: this does not handle stream params (should use index...)
+ if (!mMyParams.count(param->index())) {
+ continue; // not my param
+ }
+
+ C2Param & myParam = mMyParams.find(param->index())->second;
+ if (myParam.size() != param->size()) { // incorrect size
+ param->invalidate();
+ continue;
+ }
+
+ param->updateFrom(myParam);
+ }
+
+ for (const C2Param::Index index : heapParamIndices) {
+ if (mMyParams.count(index)) {
+ C2Param & myParam = mMyParams.find(index)->second;
+ std::unique_ptr<C2Param> paramCopy(C2Param::Copy(myParam));
+ heapParams->push_back(std::move(paramCopy));
+ }
+ }
+
+ return C2_OK;
+ }
+
+ std::unordered_map<uint32_t, C2Param &> mMyParams;
+
+ C2ComponentDomainInfo mDomainInfo;
+
+ MyComponentInstance() {
+ mMyParams.insert({mDomainInfo.index(), mDomainInfo});
+ }
+
+ virtual c2_status_t releaseTunnel_sm(c2_node_id_t targetComponent) override {
+ (void)targetComponent;
+ return C2_OMITTED;
+ }
+
+ class MyParamReflector : public C2ParamReflector {
+ const MyComponentInstance *instance;
+
+ public:
+ MyParamReflector(const MyComponentInstance *i) : instance(i) { }
+
+ virtual std::unique_ptr<C2StructDescriptor> describe(C2Param::CoreIndex paramIndex) const override {
+ switch (paramIndex.typeIndex()) {
+ case decltype(instance->mDomainInfo)::CORE_INDEX:
+ default:
+ return std::unique_ptr<C2StructDescriptor>(new C2StructDescriptor{
+ instance->mDomainInfo.type(),
+ decltype(instance->mDomainInfo)::FieldList(),
+ });
+ }
+ return nullptr;
+ }
+ };
+
+ virtual c2_status_t querySupportedValues_vb(
+ std::vector<C2FieldSupportedValuesQuery> &fields,
+ c2_blocking_t mayBlock) const override {
+ (void)mayBlock;
+ for (C2FieldSupportedValuesQuery &query : fields) {
+ if (query.field() == C2ParamField(&mDomainInfo, &C2ComponentDomainInfo::value)) {
+ query.values = C2FieldSupportedValues(
+ false /* flag */,
+ &mDomainInfo.value
+ //,
+ //{(int32_t)C2DomainVideo}
+ );
+ query.status = C2_OK;
+ } else {
+ query.status = C2_BAD_INDEX;
+ }
+ }
+ return C2_OK;
+ }
+
+ std::shared_ptr<C2ParamReflector> getParamReflector() const {
+ return std::shared_ptr<C2ParamReflector>(new MyParamReflector(this));
+ }
+
+ virtual c2_status_t querySupportedParams_nb(
+ std::vector<std::shared_ptr<C2ParamDescriptor>> * const params) const override {
+ params->push_back(std::make_shared<C2ParamDescriptor>(
+ true /* required */, "_domain", &mDomainInfo));
+ params->push_back(std::shared_ptr<C2ParamDescriptor>(
+ new C2ParamDescriptor(true /* required */, "_domain", &mDomainInfo)));
+ return C2_OK;
+ }
+
+ virtual ~MyComponentInstance() override = default;
+};
+
+template<typename E, bool S=std::is_enum<E>::value>
+struct getter {
+ int32_t get(const C2FieldSupportedValues::Primitive &p, int32_t*) {
+ return p.i32;
+ }
+ int64_t get(const C2FieldSupportedValues::Primitive &p, int64_t*) {
+ return p.i64;
+ }
+ uint32_t get(const C2FieldSupportedValues::Primitive &p, uint32_t*) {
+ return p.u32;
+ }
+ uint64_t get(const C2FieldSupportedValues::Primitive &p, uint64_t*) {
+ return p.u64;
+ }
+ float get(const C2FieldSupportedValues::Primitive &p, float*) {
+ return p.fp;
+ }
+};
+
+template<typename E>
+struct getter<E, true> {
+ typename std::underlying_type<E>::type get(const C2FieldSupportedValues::Primitive &p, E*) {
+ using u=typename std::underlying_type<E>::type;
+ return getter<u>().get(p, (u*)0);
+ }
+};
+
+template<typename T, bool E=std::is_enum<T>::value>
+struct lax_underlying_type {
+ typedef typename std::underlying_type<T>::type type;
+};
+
+template<typename T>
+struct lax_underlying_type<T, false> {
+ typedef T type;
+};
+
+template<typename E>
+typename lax_underlying_type<E>::type get(
+ const C2FieldSupportedValues::Primitive &p, E*) {
+ return getter<E>().get(p, (E*)0);
+}
+
+template<typename T>
+void dumpFSV(const C2FieldSupportedValues &sv, T*t) {
+ using namespace std;
+ cout << (std::is_enum<T>::value ? (std::is_signed<typename lax_underlying_type<T>::type>::value ? "i" : "u")
+ : std::is_integral<T>::value ? std::is_signed<T>::value ? "i" : "u" : "f")
+ << (8 * sizeof(T));
+ if (sv.type == sv.RANGE) {
+ cout << ".range(" << get(sv.range.min, t);
+ if (get(sv.range.step, t) != std::is_integral<T>::value) {
+ cout << ":" << get(sv.range.step, t);
+ }
+ if (get(sv.range.num, t) != 1 || get(sv.range.denom, t) != 1) {
+ cout << ":" << get(sv.range.num, t) << "/" << get(sv.range.denom, t);
+ }
+ cout << get(sv.range.max, t) << ")";
+ }
+ if (sv.values.size()) {
+ cout << (sv.type == sv.FLAGS ? ".flags(" : ".list(");
+ const char *sep = "";
+ for (const C2FieldSupportedValues::Primitive &p : sv.values) {
+ cout << sep << get(p, t);
+ sep = ",";
+ }
+ cout << ")";
+ }
+ cout << endl;
+}
+
+void dumpType(C2Param::Type type) {
+ using namespace std;
+ cout << (type.isVendor() ? "Vendor" : "C2");
+ if (type.forInput()) {
+ cout << "Input";
+ } else if (type.forOutput()) {
+ cout << "Output";
+ } else if (type.forPort() && !type.forStream()) {
+ cout << "Port";
+ }
+ if (type.forStream()) {
+ cout << "Stream";
+ }
+
+ if (type.isFlexible()) {
+ cout << "Flex";
+ }
+
+ cout << type.typeIndex();
+
+ switch (type.kind()) {
+ case C2Param::INFO: cout << "Info"; break;
+ case C2Param::SETTING: cout << "Setting"; break;
+ case C2Param::TUNING: cout << "Tuning"; break;
+ case C2Param::STRUCT: cout << "Struct"; break;
+ default: cout << "Kind" << (int32_t)type.kind(); break;
+ }
+}
+
+void dumpType(C2Param::CoreIndex type) {
+ using namespace std;
+ cout << (type.isVendor() ? "Vendor" : "C2");
+ if (type.isFlexible()) {
+ cout << "Flex";
+ }
+
+ cout << type.typeIndex() << "Struct";
+}
+
+void dumpType(C2FieldDescriptor::type_t type) {
+ using namespace std;
+ switch (type) {
+ case C2FieldDescriptor::BLOB: cout << "blob "; break;
+ case C2FieldDescriptor::FLOAT: cout << "float "; break;
+ case C2FieldDescriptor::INT32: cout << "int32_t "; break;
+ case C2FieldDescriptor::INT64: cout << "int64_t "; break;
+ case C2FieldDescriptor::UINT32: cout << "uint32_t "; break;
+ case C2FieldDescriptor::UINT64: cout << "uint64_t "; break;
+ case C2FieldDescriptor::STRING: cout << "char "; break;
+ default:
+ cout << "struct ";
+ dumpType((C2Param::Type)type);
+ break;
+ }
+}
+
+void dumpStruct(const C2StructDescriptor &sd) {
+ using namespace std;
+ cout << "struct ";
+ dumpType(sd.coreIndex());
+ cout << " {" << endl;
+ //C2FieldDescriptor &f;
+ for (const C2FieldDescriptor &f : sd) {
+ PrintTo(f, &cout);
+ cout << endl;
+
+ if (f.namedValues().size()) {
+ cout << ".named(";
+ const char *sep = "";
+ for (const C2FieldDescriptor::NamedValueType &p : f.namedValues()) {
+ cout << sep << p.first << "=";
+ switch (f.type()) {
+ case C2FieldDescriptor::INT32: cout << get(p.second, (int32_t *)0); break;
+ case C2FieldDescriptor::INT64: cout << get(p.second, (int64_t *)0); break;
+ case C2FieldDescriptor::UINT32: cout << get(p.second, (uint32_t *)0); break;
+ case C2FieldDescriptor::UINT64: cout << get(p.second, (uint64_t *)0); break;
+ case C2FieldDescriptor::FLOAT: cout << get(p.second, (float *)0); break;
+ default: cout << "???"; break;
+ }
+ sep = ",";
+ }
+ cout << ")";
+ }
+ }
+
+ cout << "};" << endl;
+}
+
+void dumpDesc(const C2ParamDescriptor &pd) {
+ using namespace std;
+ if (pd.isRequired()) {
+ cout << "required ";
+ }
+ if (pd.isPersistent()) {
+ cout << "persistent ";
+ }
+ cout << "struct ";
+ dumpType(C2Param::Type(pd.index().type()));
+ cout << " " << pd.name() << ";" << endl;
+}
+
+TEST_F(C2SampleComponentTest, ReflectorTest) {
+ C2ComponentDomainInfo domainInfo;
+ std::shared_ptr<MyComponentInstance> myComp(new MyComponentInstance);
+ std::shared_ptr<C2ComponentInterface> comp = myComp;
+
+ std::unique_ptr<C2StructDescriptor> desc{
+ myComp->getParamReflector()->describe(C2ComponentDomainInfo::CORE_INDEX)};
+ dumpStruct(*desc);
+
+ std::vector<C2FieldSupportedValuesQuery> query = {
+ { C2ParamField(&domainInfo, &C2ComponentDomainInfo::value),
+ C2FieldSupportedValuesQuery::CURRENT },
+ C2FieldSupportedValuesQuery(C2ParamField(&domainInfo, &C2ComponentDomainInfo::value),
+ C2FieldSupportedValuesQuery::CURRENT),
+ C2FieldSupportedValuesQuery::Current(C2ParamField(&domainInfo, &C2ComponentDomainInfo::value)),
+ };
+
+ EXPECT_EQ(C2_OK, comp->querySupportedValues_vb(query, C2_DONT_BLOCK));
+
+ for (const C2FieldSupportedValuesQuery &q : query) {
+ dumpFSV(q.values, &domainInfo.value);
+ }
+}
+
+TEST_F(C2SampleComponentTest, FieldSupportedValuesTest) {
+ typedef C2GlobalParam<C2Info, C2Uint32Value, 0> Uint32TestInfo;
+ Uint32TestInfo t;
+ std::vector<C2FieldSupportedValues> values;
+ values.push_back(C2FieldSupportedValues(0, 10, 1)); // min, max, step
+ values.push_back(C2FieldSupportedValues(1, 64, 2, 1)); // min, max, num, den
+ values.push_back(C2FieldSupportedValues(false, {1, 2, 3})); // flags, std::initializer_list
+ uint32_t val[] = {1, 3, 5, 7};
+ std::vector<uint32_t> v(std::begin(val), std::end(val));
+ values.push_back(C2FieldSupportedValues(false, v)); // flags, std::vector
+
+ for (const C2FieldSupportedValues &sv : values) {
+ dumpFSV(sv, &t.value);
+ }
+}
+