/* * 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 C2Value::INT32: cout << get(p.second, (int32_t *)0); break; case C2Value::INT64: cout << get(p.second, (int64_t *)0); break; case C2Value::UINT32: cout << get(p.second, (uint32_t *)0); break; case C2Value::UINT64: cout << get(p.second, (uint64_t *)0); break; case C2Value::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); } }