CCodec: handle vendor parameters

Bug: 142705928
Test: atest ccodec_unit_test:CCodecConfigTest
Change-Id: Ib3fe12d8e6f6785567c9f0ebd74e8ffce6a84322
gugelfrei
Wonsik Kim 5 years ago
parent 86f5034e60
commit 8a6ed3748b

@ -668,7 +668,7 @@ void CCodec::allocate(const sp<MediaCodecInfo> &codecInfo) {
// initialize config here in case setParameters is called prior to configure
Mutexed<std::unique_ptr<Config>>::Locked configLocked(mConfig);
const std::unique_ptr<Config> &config = *configLocked;
status_t err = config->initialize(mClient, comp);
status_t err = config->initialize(mClient->getParamReflector(), comp);
if (err != OK) {
ALOGW("Failed to initialize configuration support");
// TODO: report error once we complete implementation.
@ -884,6 +884,13 @@ void CCodec::configure(const sp<AMessage> &msg) {
}
}
int32_t subscribeToAllVendorParams;
if (msg->findInt32("x-*", &subscribeToAllVendorParams) && subscribeToAllVendorParams) {
if (config->subscribeToAllVendorParams(comp, C2_MAY_BLOCK) != OK) {
ALOGD("[%s] Failed to subscribe to all vendor params", comp->getName().c_str());
}
}
std::vector<std::unique_ptr<C2Param>> configUpdate;
// NOTE: We used to ignore "video-bitrate" at configure; replicate
// the behavior here.
@ -1192,7 +1199,7 @@ status_t CCodec::setupInputSurface(const std::shared_ptr<InputSurfaceWrapper> &s
// we are now using surface - apply default color aspects to input format - as well as
// get dataspace
bool inputFormatChanged = config->updateFormats(config->IS_INPUT);
bool inputFormatChanged = config->updateFormats(Config::IS_INPUT);
ALOGD("input format %s to %s",
inputFormatChanged ? "changed" : "unchanged",
config->mInputFormat->debugString().c_str());
@ -1207,7 +1214,7 @@ status_t CCodec::setupInputSurface(const std::shared_ptr<InputSurfaceWrapper> &s
if (err != OK) {
// undo input format update
config->mUsingSurface = false;
(void)config->updateFormats(config->IS_INPUT);
(void)config->updateFormats(Config::IS_INPUT);
return err;
}
config->mInputSurface = surface;
@ -1617,7 +1624,8 @@ void CCodec::signalSetParameters(const sp<AMessage> &msg) {
* Handle input surface parameters
*/
if ((config->mDomain & (Config::IS_VIDEO | Config::IS_IMAGE))
&& (config->mDomain & Config::IS_ENCODER) && config->mInputSurface && config->mISConfig) {
&& (config->mDomain & Config::IS_ENCODER)
&& config->mInputSurface && config->mISConfig) {
(void)params->findInt64(PARAMETER_KEY_OFFSET_TIME, &config->mISConfig->mTimeOffsetUs);
if (params->findInt64("skip-frames-before", &config->mISConfig->mStartAtUs)) {

@ -20,7 +20,6 @@
#include <log/log.h>
#include <C2Component.h>
#include <C2Debug.h>
#include <C2Param.h>
#include <util/C2InterfaceHelper.h>
@ -49,6 +48,27 @@ namespace android {
namespace {
void C2ValueToMessageItem(const C2Value &value, AMessage::ItemData &item) {
int32_t int32Value;
uint32_t uint32Value;
int64_t int64Value;
uint64_t uint64Value;
float floatValue;
if (value.get(&int32Value)) {
item.set(int32Value);
} else if (value.get(&uint32Value) && uint32Value <= uint32_t(INT32_MAX)) {
// SDK does not support unsigned values
item.set((int32_t)uint32Value);
} else if (value.get(&int64Value)) {
item.set(int64Value);
} else if (value.get(&uint64Value) && uint64Value <= uint64_t(INT64_MAX)) {
// SDK does not support unsigned values
item.set((int64_t)uint64Value);
} else if (value.get(&floatValue)) {
item.set(floatValue);
}
}
/**
* mapping between SDK and Codec 2.0 configurations.
*/
@ -138,27 +158,10 @@ struct ConfigMapper {
/// Maps from a C2Value to an SDK value in an AMessage.
AMessage::ItemData mapToMessage(C2Value value) const {
AMessage::ItemData item;
int32_t int32Value;
uint32_t uint32Value;
int64_t int64Value;
uint64_t uint64Value;
float floatValue;
if (value.type() != C2Value::NO_INIT && mReverse) {
value = mReverse(value);
}
if (value.get(&int32Value)) {
item.set(int32Value);
} else if (value.get(&uint32Value) && uint32Value <= uint32_t(INT32_MAX)) {
// SDK does not support unsigned values
item.set((int32_t)uint32Value);
} else if (value.get(&int64Value)) {
item.set(int64Value);
} else if (value.get(&uint64Value) && uint64Value <= uint64_t(INT64_MAX)) {
// SDK does not support unsigned values
item.set((int64_t)uint64Value);
} else if (value.get(&floatValue)) {
item.set(floatValue);
}
C2ValueToMessageItem(value, item);
return item;
}
@ -179,10 +182,10 @@ private:
template <typename PORT, typename STREAM>
AString QueryMediaTypeImpl(
const std::shared_ptr<Codec2Client::Component> &component) {
const std::shared_ptr<Codec2Client::Configurable> &configurable) {
AString mediaType;
std::vector<std::unique_ptr<C2Param>> queried;
c2_status_t c2err = component->query(
c2_status_t c2err = configurable->query(
{}, { PORT::PARAM_TYPE, STREAM::PARAM_TYPE }, C2_DONT_BLOCK, &queried);
if (c2err != C2_OK && queried.size() == 0) {
ALOGD("Query media type failed => %s", asString(c2err));
@ -207,13 +210,13 @@ AString QueryMediaTypeImpl(
}
AString QueryMediaType(
bool input, const std::shared_ptr<Codec2Client::Component> &component) {
bool input, const std::shared_ptr<Codec2Client::Configurable> &configurable) {
typedef C2PortMediaTypeSetting P;
typedef C2StreamMediaTypeSetting S;
if (input) {
return QueryMediaTypeImpl<P::input, S::input>(component);
return QueryMediaTypeImpl<P::input, S::input>(configurable);
} else {
return QueryMediaTypeImpl<P::output, S::output>(component);
return QueryMediaTypeImpl<P::output, S::output>(configurable);
}
}
@ -825,27 +828,27 @@ void CCodecConfig::initializeStandardParams() {
}
status_t CCodecConfig::initialize(
const std::shared_ptr<Codec2Client> &client,
const std::shared_ptr<Codec2Client::Component> &component) {
const std::shared_ptr<C2ParamReflector> &reflector,
const std::shared_ptr<Codec2Client::Configurable> &configurable) {
C2ComponentDomainSetting domain(C2Component::DOMAIN_OTHER);
C2ComponentKindSetting kind(C2Component::KIND_OTHER);
std::vector<std::unique_ptr<C2Param>> queried;
c2_status_t c2err = component->query({ &domain, &kind }, {}, C2_DONT_BLOCK, &queried);
c2_status_t c2err = configurable->query({ &domain, &kind }, {}, C2_DONT_BLOCK, &queried);
if (c2err != C2_OK) {
ALOGD("Query domain & kind failed => %s", asString(c2err));
// TEMP: determine kind from component name
if (kind.value == C2Component::KIND_OTHER) {
if (component->getName().find("encoder") != std::string::npos) {
if (configurable->getName().find("encoder") != std::string::npos) {
kind.value = C2Component::KIND_ENCODER;
} else if (component->getName().find("decoder") != std::string::npos) {
} else if (configurable->getName().find("decoder") != std::string::npos) {
kind.value = C2Component::KIND_DECODER;
}
}
// TEMP: determine domain from media type (port (preferred) or stream #0)
if (domain.value == C2Component::DOMAIN_OTHER) {
AString mediaType = QueryMediaType(true /* input */, component);
AString mediaType = QueryMediaType(true /* input */, configurable);
if (mediaType.startsWith("audio/")) {
domain.value = C2Component::DOMAIN_AUDIO;
} else if (mediaType.startsWith("video/")) {
@ -870,16 +873,16 @@ status_t CCodecConfig::initialize(
std::vector<C2Param::Index> paramIndices;
switch (kind.value) {
case C2Component::KIND_DECODER:
mCodingMediaType = QueryMediaType(true /* input */, component).c_str();
mCodingMediaType = QueryMediaType(true /* input */, configurable).c_str();
break;
case C2Component::KIND_ENCODER:
mCodingMediaType = QueryMediaType(false /* input */, component).c_str();
mCodingMediaType = QueryMediaType(false /* input */, configurable).c_str();
break;
default:
mCodingMediaType = "";
}
c2err = component->querySupportedParams(&mParamDescs);
c2err = configurable->querySupportedParams(&mParamDescs);
if (c2err != C2_OK) {
ALOGD("Query supported params failed after returning %zu values => %s",
mParamDescs.size(), asString(c2err));
@ -889,9 +892,9 @@ status_t CCodecConfig::initialize(
mSupportedIndices.emplace(desc->index());
}
mReflector = client->getParamReflector();
mReflector = reflector;
if (mReflector == nullptr) {
ALOGE("Failed to get param reflector");
ALOGE("Null param reflector");
return UNKNOWN_ERROR;
}
@ -945,11 +948,21 @@ status_t CCodecConfig::initialize(
// init data (CSD)
mSubscribedIndices.emplace(C2StreamInitDataInfo::output::PARAM_TYPE);
for (const std::shared_ptr<C2ParamDescriptor> &desc : mParamDescs) {
if (desc->index().isVendor()) {
std::vector<std::string> keys;
mParamUpdater->getKeysForParamIndex(desc->index(), &keys);
for (const std::string &key : keys) {
mVendorParamIndices.insert_or_assign(key, desc->index());
}
}
}
return OK;
}
status_t CCodecConfig::subscribeToConfigUpdate(
const std::shared_ptr<Codec2Client::Component> &component,
const std::shared_ptr<Codec2Client::Configurable> &configurable,
const std::vector<C2Param::Index> &indices,
c2_blocking_t blocking) {
mSubscribedIndices.insert(indices.begin(), indices.end());
@ -962,7 +975,7 @@ status_t CCodecConfig::subscribeToConfigUpdate(
std::unique_ptr<C2SubscribedParamIndicesTuning> subscribeTuning =
C2SubscribedParamIndicesTuning::AllocUnique(indices);
std::vector<std::unique_ptr<C2SettingResult>> results;
c2_status_t c2Err = component->config({ subscribeTuning.get() }, blocking, &results);
c2_status_t c2Err = configurable->config({ subscribeTuning.get() }, blocking, &results);
if (c2Err != C2_OK && c2Err != C2_BAD_INDEX) {
ALOGD("Failed to subscribe to parameters => %s", asString(c2Err));
// TODO: error
@ -974,11 +987,11 @@ status_t CCodecConfig::subscribeToConfigUpdate(
}
status_t CCodecConfig::queryConfiguration(
const std::shared_ptr<Codec2Client::Component> &component) {
const std::shared_ptr<Codec2Client::Configurable> &configurable) {
// query all subscribed parameters
std::vector<C2Param::Index> indices(mSubscribedIndices.begin(), mSubscribedIndices.end());
std::vector<std::unique_ptr<C2Param>> queried;
c2_status_t c2Err = component->query({}, indices, C2_MAY_BLOCK, &queried);
c2_status_t c2Err = configurable->query({}, indices, C2_MAY_BLOCK, &queried);
if (c2Err != OK) {
ALOGI("query failed after returning %zu values (%s)", queried.size(), asString(c2Err));
// TODO: error
@ -1048,7 +1061,7 @@ bool CCodecConfig::updateFormats(Domain domain) {
if (domain & mInputDomain) {
sp<AMessage> oldFormat = mInputFormat;
mInputFormat = mInputFormat->dup(); // trigger format changed
mInputFormat->extend(getSdkFormatForDomain(reflected, mInputDomain));
mInputFormat->extend(getFormatForDomain(reflected, mInputDomain));
if (mInputFormat->countEntries() != oldFormat->countEntries()
|| mInputFormat->changesFrom(oldFormat)->countEntries() > 0) {
changed = true;
@ -1059,7 +1072,7 @@ bool CCodecConfig::updateFormats(Domain domain) {
if (domain & mOutputDomain) {
sp<AMessage> oldFormat = mOutputFormat;
mOutputFormat = mOutputFormat->dup(); // trigger output format changed
mOutputFormat->extend(getSdkFormatForDomain(reflected, mOutputDomain));
mOutputFormat->extend(getFormatForDomain(reflected, mOutputDomain));
if (mOutputFormat->countEntries() != oldFormat->countEntries()
|| mOutputFormat->changesFrom(oldFormat)->countEntries() > 0) {
changed = true;
@ -1071,8 +1084,9 @@ bool CCodecConfig::updateFormats(Domain domain) {
return changed;
}
sp<AMessage> CCodecConfig::getSdkFormatForDomain(
const ReflectedParamUpdater::Dict &reflected, Domain portDomain) const {
sp<AMessage> CCodecConfig::getFormatForDomain(
const ReflectedParamUpdater::Dict &reflected,
Domain portDomain) const {
sp<AMessage> msg = new AMessage;
for (const std::pair<std::string, std::vector<ConfigMapper>> &el : mStandardParams->getKeys()) {
for (const ConfigMapper &cm : el.second) {
@ -1103,6 +1117,39 @@ sp<AMessage> CCodecConfig::getSdkFormatForDomain(
}
}
bool input = (portDomain & Domain::IS_INPUT);
std::vector<std::string> vendorKeys;
for (const std::pair<std::string, ReflectedParamUpdater::Value> &entry : reflected) {
auto it = mVendorParamIndices.find(entry.first);
if (it == mVendorParamIndices.end()) {
continue;
}
if (mSubscribedIndices.count(it->second) == 0) {
continue;
}
// For vendor parameters, we only care about direction
if ((input && !it->second.forInput())
|| (!input && !it->second.forOutput())) {
continue;
}
const ReflectedParamUpdater::Value &value = entry.second;
C2Value c2Value;
sp<ABuffer> bufValue;
AString strValue;
AMessage::ItemData item;
if (value.find(&c2Value)) {
C2ValueToMessageItem(c2Value, item);
} else if (value.find(&bufValue)) {
item.set(bufValue);
} else if (value.find(&strValue)) {
item.set(strValue);
} else {
ALOGD("unexpected untyped query value for key: %s", entry.first.c_str());
continue;
}
msg->setItem(entry.first.c_str(), item);
}
{ // convert from Codec 2.0 rect to MediaFormat rect and add crop rect if not present
int32_t left, top, width, height;
if (msg->findInt32("crop-left", &left) && msg->findInt32("crop-width", &width)
@ -1510,7 +1557,7 @@ ReflectedParamUpdater::Dict CCodecConfig::getReflectedFormat(
}
status_t CCodecConfig::getConfigUpdateFromSdkParams(
std::shared_ptr<Codec2Client::Component> component,
std::shared_ptr<Codec2Client::Configurable> configurable,
const sp<AMessage> &sdkParams, Domain configDomain,
c2_blocking_t blocking,
std::vector<std::unique_ptr<C2Param>> *configUpdate) const {
@ -1537,7 +1584,7 @@ status_t CCodecConfig::getConfigUpdateFromSdkParams(
}
}
c2_status_t err = component->query({ }, supportedIndices, blocking, configUpdate);
c2_status_t err = configurable->query({ }, supportedIndices, blocking, configUpdate);
if (err != C2_OK) {
ALOGD("query failed after returning %zu params => %s", configUpdate->size(), asString(err));
}
@ -1549,7 +1596,7 @@ status_t CCodecConfig::getConfigUpdateFromSdkParams(
}
status_t CCodecConfig::setParameters(
std::shared_ptr<Codec2Client::Component> component,
std::shared_ptr<Codec2Client::Configurable> configurable,
std::vector<std::unique_ptr<C2Param>> &configUpdate,
c2_blocking_t blocking) {
status_t result = OK;
@ -1585,10 +1632,10 @@ status_t CCodecConfig::setParameters(
}
}
// update subscribed param indices
subscribeToConfigUpdate(component, indices, blocking);
subscribeToConfigUpdate(configurable, indices, blocking);
std::vector<std::unique_ptr<C2SettingResult>> failures;
c2_status_t err = component->config(paramVector, blocking, &failures);
c2_status_t err = configurable->config(paramVector, blocking, &failures);
if (err != C2_OK) {
ALOGD("config failed => %s", asString(err));
// This is non-fatal.
@ -1608,7 +1655,7 @@ status_t CCodecConfig::setParameters(
// Re-query parameter values in case config could not update them and update the current
// configuration.
configUpdate.clear();
err = component->query({}, indices, blocking, &configUpdate);
err = configurable->query({}, indices, blocking, &configUpdate);
if (err != C2_OK) {
ALOGD("query failed after returning %zu params => %s", configUpdate.size(), asString(err));
}
@ -1627,4 +1674,13 @@ const C2Param *CCodecConfig::getConfigParameterValue(C2Param::Index index) const
}
}
status_t CCodecConfig::subscribeToAllVendorParams(
const std::shared_ptr<Codec2Client::Configurable> &configurable,
c2_blocking_t blocking) {
for (const std::pair<std::string, C2Param::Index> &entry : mVendorParamIndices) {
mSubscribedIndices.insert(entry.second);
}
return subscribeToConfigUpdate(configurable, {}, blocking);
}
} // namespace android

@ -23,8 +23,10 @@
#include <vector>
#include <C2Component.h>
#include <codec2/hidl/client.h>
#include <C2Config.h>
#include <C2Debug.h>
#include <codec2/hidl/client.h>
#include <utils/RefBase.h>
#include "InputSurfaceWrapper.h"
@ -39,7 +41,6 @@ struct StandardParams;
* Struct managing the codec configuration for CCodec.
*/
struct CCodecConfig {
/**
* Domain consists of a bitmask divided into fields, and specifiers work by excluding other
* values in those domains.
@ -135,6 +136,9 @@ struct CCodecConfig {
/// For now support a validation function.
std::map<C2Param::Index, LocalParamValidator> mLocalParams;
/// Vendor field name -> index map.
std::map<std::string, C2Param::Index> mVendorParamIndices;
std::set<std::string> mLastConfig;
CCodecConfig();
@ -143,9 +147,8 @@ struct CCodecConfig {
/// reflected param helper, domain, standard params, and subscribes to standard
/// indices.
status_t initialize(
const std::shared_ptr<Codec2Client> &client,
const std::shared_ptr<Codec2Client::Component> &component);
const std::shared_ptr<C2ParamReflector> &client,
const std::shared_ptr<Codec2Client::Configurable> &configurable);
/**
* Adds a locally maintained parameter. This is used for output configuration that can be
@ -238,7 +241,7 @@ struct CCodecConfig {
* \param blocking blocking mode to use with the component
*/
status_t getConfigUpdateFromSdkParams(
std::shared_ptr<Codec2Client::Component> component,
std::shared_ptr<Codec2Client::Configurable> configurable,
const sp<AMessage> &sdkParams, Domain domain,
c2_blocking_t blocking,
std::vector<std::unique_ptr<C2Param>> *configUpdate) const;
@ -250,19 +253,24 @@ struct CCodecConfig {
* \param blocking blocking mode to use with the component
*/
status_t setParameters(
std::shared_ptr<Codec2Client::Component> component,
std::shared_ptr<Codec2Client::Configurable> configurable,
std::vector<std::unique_ptr<C2Param>> &configUpdate,
c2_blocking_t blocking);
/// Queries subscribed indices (which contains all SDK-exposed values) and updates
/// input/output formats.
status_t queryConfiguration(
const std::shared_ptr<Codec2Client::Component> &component);
const std::shared_ptr<Codec2Client::Configurable> &configurable);
/// Queries a configuration parameter value. Returns nullptr if the parameter is not
/// part of the current configuration
const C2Param *getConfigParameterValue(C2Param::Index index) const;
/// Subscribe to all vendor parameters.
status_t subscribeToAllVendorParams(
const std::shared_ptr<Codec2Client::Configurable> &configurable,
c2_blocking_t blocking);
/**
* Object that can be used to access configuration parameters and if they change.
*/
@ -321,14 +329,15 @@ private:
/// Adds indices to the subscribed indices, and updated subscription to component
/// \param blocking blocking mode to use with the component
status_t subscribeToConfigUpdate(
const std::shared_ptr<Codec2Client::Component> &component,
const std::shared_ptr<Codec2Client::Configurable> &configurable,
const std::vector<C2Param::Index> &indices,
c2_blocking_t blocking = C2_DONT_BLOCK);
/// Gets SDK format from codec 2.0 reflected configuration
/// \param domain input/output bitmask
sp<AMessage> getSdkFormatForDomain(
const ReflectedParamUpdater::Dict &reflected, Domain domain) const;
sp<AMessage> getFormatForDomain(
const ReflectedParamUpdater::Dict &reflected,
Domain domain) const;
/**
* Converts a set of configuration parameters in an AMessage to a list of path-based Codec

@ -125,18 +125,6 @@ void ReflectedParamUpdater::addParamDesc(
}
addParamDesc(desc, *structDesc, reflector, true /* markVendor */);
}
// TEMP: also add vendor parameters as non-vendor
for (const std::shared_ptr<C2ParamDescriptor> &desc : paramDescs) {
if (!desc->index().isVendor()) {
continue;
}
std::unique_ptr<C2StructDescriptor> structDesc = reflector->describe(
desc->index().coreIndex());
if (structDesc) {
addParamDesc(desc, *structDesc, reflector, false /* markVendor */);
}
}
}
void ReflectedParamUpdater::addParamStructDesc(
@ -286,6 +274,20 @@ void ReflectedParamUpdater::getParamIndicesForKeys(
}
}
void ReflectedParamUpdater::getKeysForParamIndex(
const C2Param::Index &index,
std::vector<std::string> *keys /* nonnull */) const {
CHECK(keys != nullptr);
keys->clear();
for (const std::pair<const std::string, FieldDesc> &kv : mMap) {
const std::string &name = kv.first;
const FieldDesc &desc = kv.second;
if (desc.paramDesc->index() == index) {
keys->push_back(name);
}
}
}
void ReflectedParamUpdater::updateParamsFromMessage(
const Dict &params,
std::vector<std::unique_ptr<C2Param>> *vec /* nonnull */) const {

@ -165,6 +165,16 @@ public:
const std::vector<std::string> &keys,
std::vector<C2Param::Index> *vec /* nonnull */) const;
/**
* Get list of field names for the given param index.
*
* \param index[in] param index
* \param keys[out] vector to store the field names
*/
void getKeysForParamIndex(
const C2Param::Index &index,
std::vector<std::string> *keys /* nonnull */) const;
/**
* Update C2Param objects from field name and value in AMessage object.
*

@ -189,7 +189,7 @@ private:
struct ClientListener;
Mutexed<NamedTimePoint> mDeadline;
typedef CCodecConfig Config;
Mutexed<std::unique_ptr<CCodecConfig>> mConfig;
Mutexed<std::list<std::unique_ptr<C2Work>>> mWorkDoneQueue;

@ -2,16 +2,24 @@ cc_test {
name: "ccodec_unit_test",
srcs: [
"CCodecConfig_test.cpp",
"ReflectedParamUpdater_test.cpp",
],
defaults: [
"libcodec2-hidl-defaults@1.0",
"libcodec2-internal-defaults",
],
include_dirs: [
"frameworks/av/media/codec2/sfplugin",
],
shared_libs: [
"libcodec2",
"libcodec2_client",
"libsfplugin_ccodec",
"libsfplugin_ccodec_utils",
"libstagefright_foundation",
"libutils",
],

@ -0,0 +1,311 @@
/*
* Copyright 2019 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.
*/
#include "CCodecConfig.h"
#include <set>
#include <gtest/gtest.h>
#include <codec2/hidl/1.0/Configurable.h>
#include <codec2/hidl/client.h>
#include <util/C2InterfaceHelper.h>
namespace {
enum ExtendedC2ParamIndexKind : C2Param::type_index_t {
kParamIndexVendorInt32 = C2Param::TYPE_INDEX_VENDOR_START,
kParamIndexVendorInt64,
kParamIndexVendorString,
};
typedef C2PortParam<C2Info, C2Int32Value, kParamIndexVendorInt32> C2PortVendorInt32Info;
constexpr char C2_PARAMKEY_VENDOR_INT32[] = "example.int32";
constexpr char KEY_VENDOR_INT32[] = "vendor.example.int32.value";
typedef C2StreamParam<C2Info, C2Int64Value, kParamIndexVendorInt64> C2StreamVendorInt64Info;
constexpr char C2_PARAMKEY_VENDOR_INT64[] = "example.int64";
constexpr char KEY_VENDOR_INT64[] = "vendor.example.int64.value";
typedef C2PortParam<C2Info, C2StringValue, kParamIndexVendorString> C2PortVendorStringInfo;
constexpr char C2_PARAMKEY_VENDOR_STRING[] = "example.string";
constexpr char KEY_VENDOR_STRING[] = "vendor.example.string.value";
} // namespace
namespace android {
class CCodecConfigTest : public ::testing::Test {
public:
constexpr static int32_t kCodec2Int32 = 0xC0DEC2;
constexpr static int64_t kCodec2Int64 = 0xC0DEC2C0DEC2ll;
constexpr static char kCodec2Str[] = "codec2";
CCodecConfigTest()
: mReflector{std::make_shared<C2ReflectorHelper>()} {
sp<hardware::media::c2::V1_0::utils::CachedConfigurable> cachedConfigurable =
new hardware::media::c2::V1_0::utils::CachedConfigurable(
std::make_unique<Configurable>(mReflector));
cachedConfigurable->init(std::make_shared<Cache>());
mConfigurable = std::make_shared<Codec2Client::Configurable>(cachedConfigurable);
}
struct Cache : public hardware::media::c2::V1_0::utils::ParameterCache {
c2_status_t validate(const std::vector<std::shared_ptr<C2ParamDescriptor>>&) override {
return C2_OK;
}
};
class Configurable : public hardware::media::c2::V1_0::utils::ConfigurableC2Intf {
public:
explicit Configurable(const std::shared_ptr<C2ReflectorHelper> &reflector)
: ConfigurableC2Intf("name", 0u),
mImpl(reflector) {
}
c2_status_t query(
const std::vector<C2Param::Index> &indices,
c2_blocking_t mayBlock,
std::vector<std::unique_ptr<C2Param>>* const params) const override {
return mImpl.query({}, indices, mayBlock, params);
}
c2_status_t config(
const std::vector<C2Param*> &params,
c2_blocking_t mayBlock,
std::vector<std::unique_ptr<C2SettingResult>>* const failures) override {
return mImpl.config(params, mayBlock, failures);
}
c2_status_t querySupportedParams(
std::vector<std::shared_ptr<C2ParamDescriptor>>* const params) const override {
return mImpl.querySupportedParams(params);
}
c2_status_t querySupportedValues(
std::vector<C2FieldSupportedValuesQuery>& fields,
c2_blocking_t mayBlock) const override {
return mImpl.querySupportedValues(fields, mayBlock);
}
private:
class Impl : public C2InterfaceHelper {
public:
explicit Impl(const std::shared_ptr<C2ReflectorHelper> &reflector)
: C2InterfaceHelper{reflector} {
setDerivedInstance(this);
addParameter(
DefineParam(mInt32Input, C2_PARAMKEY_VENDOR_INT32)
.withDefault(new C2PortVendorInt32Info::input(0))
.withFields({C2F(mInt32Input, value).any()})
.withSetter(Setter<decltype(mInt32Input)::element_type>)
.build());
addParameter(
DefineParam(mInt64Output, C2_PARAMKEY_VENDOR_INT64)
.withDefault(new C2StreamVendorInt64Info::output(0u, 0))
.withFields({C2F(mInt64Output, value).any()})
.withSetter(Setter<decltype(mInt64Output)::element_type>)
.build());
addParameter(
DefineParam(mStringInput, C2_PARAMKEY_VENDOR_STRING)
.withDefault(decltype(mStringInput)::element_type::AllocShared(1, ""))
.withFields({C2F(mStringInput, m.value).any()})
.withSetter(Setter<decltype(mStringInput)::element_type>)
.build());
// TODO: SDK params
}
private:
std::shared_ptr<C2PortVendorInt32Info::input> mInt32Input;
std::shared_ptr<C2StreamVendorInt64Info::output> mInt64Output;
std::shared_ptr<C2PortVendorStringInfo::input> mStringInput;
template<typename T>
static C2R Setter(bool, C2P<T> &) {
return C2R::Ok();
}
};
Impl mImpl;
};
std::shared_ptr<C2ReflectorHelper> mReflector;
std::shared_ptr<Codec2Client::Configurable> mConfigurable;
CCodecConfig mConfig;
};
using D = CCodecConfig::Domain;
template<typename T>
T *FindParam(const std::vector<std::unique_ptr<C2Param>> &vec) {
for (const std::unique_ptr<C2Param> &param : vec) {
if (param->coreIndex() == T::CORE_INDEX) {
return static_cast<T *>(param.get());
}
}
return nullptr;
}
TEST_F(CCodecConfigTest, SetVendorParam) {
ASSERT_EQ(OK, mConfig.initialize(mReflector, mConfigurable));
sp<AMessage> format{new AMessage};
format->setInt32(KEY_VENDOR_INT32, kCodec2Int32);
format->setInt64(KEY_VENDOR_INT64, kCodec2Int64);
format->setString(KEY_VENDOR_STRING, kCodec2Str);
std::vector<std::unique_ptr<C2Param>> configUpdate;
ASSERT_EQ(OK, mConfig.getConfigUpdateFromSdkParams(
mConfigurable, format, D::IS_INPUT | D::IS_OUTPUT, C2_MAY_BLOCK, &configUpdate));
ASSERT_EQ(3u, configUpdate.size());
C2PortVendorInt32Info::input *i32 =
FindParam<std::remove_pointer<decltype(i32)>::type>(configUpdate);
ASSERT_NE(nullptr, i32);
ASSERT_EQ(kCodec2Int32, i32->value);
C2StreamVendorInt64Info::output *i64 =
FindParam<std::remove_pointer<decltype(i64)>::type>(configUpdate);
ASSERT_NE(nullptr, i64);
ASSERT_EQ(kCodec2Int64, i64->value);
C2PortVendorStringInfo::input *str =
FindParam<std::remove_pointer<decltype(str)>::type>(configUpdate);
ASSERT_NE(nullptr, str);
ASSERT_STREQ(kCodec2Str, str->m.value);
}
TEST_F(CCodecConfigTest, VendorParamUpdate_Unsubscribed) {
ASSERT_EQ(OK, mConfig.initialize(mReflector, mConfigurable));
std::vector<std::unique_ptr<C2Param>> configUpdate;
C2PortVendorInt32Info::input i32(kCodec2Int32);
C2StreamVendorInt64Info::output i64(0u, kCodec2Int64);
std::unique_ptr<C2PortVendorStringInfo::input> str =
C2PortVendorStringInfo::input::AllocUnique(strlen(kCodec2Str) + 1, kCodec2Str);
configUpdate.push_back(C2Param::Copy(i32));
configUpdate.push_back(C2Param::Copy(i64));
configUpdate.push_back(std::move(str));
// The vendor parameters are not yet subscribed
ASSERT_FALSE(mConfig.updateConfiguration(configUpdate, D::IS_INPUT | D::IS_OUTPUT));
int32_t vendorInt32{0};
ASSERT_FALSE(mConfig.mInputFormat->findInt32(KEY_VENDOR_INT32, &vendorInt32))
<< "mInputFormat = " << mConfig.mInputFormat->debugString().c_str();
ASSERT_FALSE(mConfig.mOutputFormat->findInt32(KEY_VENDOR_INT32, &vendorInt32))
<< "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str();
int64_t vendorInt64{0};
ASSERT_FALSE(mConfig.mInputFormat->findInt64(KEY_VENDOR_INT64, &vendorInt64))
<< "mInputFormat = " << mConfig.mInputFormat->debugString().c_str();
ASSERT_FALSE(mConfig.mOutputFormat->findInt64(KEY_VENDOR_INT64, &vendorInt64))
<< "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str();
AString vendorString;
ASSERT_FALSE(mConfig.mInputFormat->findString(KEY_VENDOR_STRING, &vendorString))
<< "mInputFormat = " << mConfig.mInputFormat->debugString().c_str();
ASSERT_FALSE(mConfig.mOutputFormat->findString(KEY_VENDOR_STRING, &vendorString))
<< "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str();
}
TEST_F(CCodecConfigTest, VendorParamUpdate_AllSubscribed) {
ASSERT_EQ(OK, mConfig.initialize(mReflector, mConfigurable));
// Force subscribe to all vendor params
ASSERT_EQ(OK, mConfig.subscribeToAllVendorParams(mConfigurable, C2_MAY_BLOCK));
std::vector<std::unique_ptr<C2Param>> configUpdate;
C2PortVendorInt32Info::input i32(kCodec2Int32);
C2StreamVendorInt64Info::output i64(0u, kCodec2Int64);
std::unique_ptr<C2PortVendorStringInfo::input> str =
C2PortVendorStringInfo::input::AllocUnique(strlen(kCodec2Str) + 1, kCodec2Str);
configUpdate.push_back(C2Param::Copy(i32));
configUpdate.push_back(C2Param::Copy(i64));
configUpdate.push_back(std::move(str));
ASSERT_TRUE(mConfig.updateConfiguration(configUpdate, D::IS_INPUT | D::IS_OUTPUT));
int32_t vendorInt32{0};
ASSERT_TRUE(mConfig.mInputFormat->findInt32(KEY_VENDOR_INT32, &vendorInt32))
<< "mInputFormat = " << mConfig.mInputFormat->debugString().c_str();
ASSERT_EQ(kCodec2Int32, vendorInt32);
ASSERT_FALSE(mConfig.mOutputFormat->findInt32(KEY_VENDOR_INT32, &vendorInt32))
<< "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str();
int64_t vendorInt64{0};
ASSERT_FALSE(mConfig.mInputFormat->findInt64(KEY_VENDOR_INT64, &vendorInt64))
<< "mInputFormat = " << mConfig.mInputFormat->debugString().c_str();
ASSERT_TRUE(mConfig.mOutputFormat->findInt64(KEY_VENDOR_INT64, &vendorInt64))
<< "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str();
ASSERT_EQ(kCodec2Int64, vendorInt64);
AString vendorString;
ASSERT_TRUE(mConfig.mInputFormat->findString(KEY_VENDOR_STRING, &vendorString))
<< "mInputFormat = " << mConfig.mInputFormat->debugString().c_str();
ASSERT_STREQ(kCodec2Str, vendorString.c_str());
ASSERT_FALSE(mConfig.mOutputFormat->findString(KEY_VENDOR_STRING, &vendorString))
<< "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str();
}
TEST_F(CCodecConfigTest, VendorParamUpdate_PartiallySubscribed) {
ASSERT_EQ(OK, mConfig.initialize(mReflector, mConfigurable));
// Subscribe to example.int32 only
std::vector<std::unique_ptr<C2Param>> configUpdate;
sp<AMessage> format{new AMessage};
format->setInt32(KEY_VENDOR_INT32, 0);
configUpdate.clear();
ASSERT_EQ(OK, mConfig.getConfigUpdateFromSdkParams(
mConfigurable, format, D::IS_INPUT | D::IS_OUTPUT, C2_MAY_BLOCK, &configUpdate));
ASSERT_EQ(OK, mConfig.setParameters(mConfigurable, configUpdate, C2_MAY_BLOCK));
C2PortVendorInt32Info::input i32(kCodec2Int32);
C2StreamVendorInt64Info::output i64(0u, kCodec2Int64);
std::unique_ptr<C2PortVendorStringInfo::input> str =
C2PortVendorStringInfo::input::AllocUnique(strlen(kCodec2Str) + 1, kCodec2Str);
configUpdate.clear();
configUpdate.push_back(C2Param::Copy(i32));
configUpdate.push_back(C2Param::Copy(i64));
configUpdate.push_back(std::move(str));
// Only example.i32 should be updated
ASSERT_TRUE(mConfig.updateConfiguration(configUpdate, D::IS_INPUT | D::IS_OUTPUT));
int32_t vendorInt32{0};
ASSERT_TRUE(mConfig.mInputFormat->findInt32(KEY_VENDOR_INT32, &vendorInt32))
<< "mInputFormat = " << mConfig.mInputFormat->debugString().c_str();
ASSERT_EQ(kCodec2Int32, vendorInt32);
ASSERT_FALSE(mConfig.mOutputFormat->findInt32(KEY_VENDOR_INT32, &vendorInt32))
<< "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str();
int64_t vendorInt64{0};
ASSERT_FALSE(mConfig.mInputFormat->findInt64(KEY_VENDOR_INT64, &vendorInt64))
<< "mInputFormat = " << mConfig.mInputFormat->debugString().c_str();
ASSERT_FALSE(mConfig.mOutputFormat->findInt64(KEY_VENDOR_INT64, &vendorInt64))
<< "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str();
AString vendorString;
ASSERT_FALSE(mConfig.mInputFormat->findString(KEY_VENDOR_STRING, &vendorString))
<< "mInputFormat = " << mConfig.mInputFormat->debugString().c_str();
ASSERT_FALSE(mConfig.mOutputFormat->findString(KEY_VENDOR_STRING, &vendorString))
<< "mOutputFormat = " << mConfig.mOutputFormat->debugString().c_str();
}
} // namespace android
Loading…
Cancel
Save