/* * Copyright (C) 2018 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef C_CODEC_CONFIG_H_ #define C_CODEC_CONFIG_H_ #include #include #include #include #include #include #include #include #include #include "InputSurfaceWrapper.h" #include "ReflectedParamUpdater.h" namespace android { struct AMessage; struct CodecParameterDescriptor; class NativeHandle; 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. * * Component domains are composed by or-ing the individual IS_ constants, e.g. * IS_DECODER | IS_AUDIO. * * Config specifiers are composed by or-ing the individual mask constants, and * and-ing these groups: e.g. (DECODER | ENCODER) & AUDIO. * * The naming of these constants was to limit the length of mask names as these are used more * commonly as masks. */ enum Domain : uint32_t { // component domain (domain & kind) GUARD_BIT = (1 << 1), ///< this is to prevent against accidental && or || usage IS_AUDIO = (1 << 2), ///< for audio codecs IS_VIDEO = (1 << 3), ///< for video codecs IS_IMAGE = (1 << 4), ///< for image codecs OTHER_DOMAIN = (1 << 5), ///< for other domains IS_ENCODER = (1 << 6), ///< for encoders IS_DECODER = (1 << 7), ///< for decoders OTHER_KIND = (1 << 8), ///< for other domains // config domain IS_PARAM = (1 << 9), ///< for setParameter IS_CONFIG = (1 << 10), ///< for configure IS_READ = (1 << 11), ///< for getFormat // port domain IS_INPUT = (1 << 12), ///< for input port (getFormat) IS_OUTPUT = (1 << 13), ///< for output port (getFormat) IS_RAW = (1 << 14), ///< for raw port (input-encoder, output-decoder) IS_CODED = (1 << 15), ///< for coded port (input-decoder, output-encoder) ALL = ~0U, NONE = 0, AUDIO = ~(IS_IMAGE | IS_VIDEO | OTHER_DOMAIN), VIDEO = ~(IS_AUDIO | IS_IMAGE | OTHER_DOMAIN), IMAGE = ~(IS_AUDIO | IS_VIDEO | OTHER_DOMAIN), DECODER = ~(IS_ENCODER | OTHER_KIND), ENCODER = ~(IS_DECODER | OTHER_KIND), PARAM = ~(IS_CONFIG | IS_READ), CONFIG = ~(IS_PARAM | IS_READ), READ = ~(IS_CONFIG | IS_PARAM), INPUT = ~(IS_OUTPUT | IS_RAW | IS_CODED), OUTPUT = ~(IS_INPUT | IS_RAW | IS_CODED), RAW = ~(IS_INPUT | IS_OUTPUT | IS_CODED), CODED = ~(IS_INPUT | IS_RAW | IS_OUTPUT), }; // things required to manage formats std::vector> mParamDescs; std::shared_ptr mReflector; std::shared_ptr mParamUpdater; Domain mDomain; // component domain Domain mInputDomain; // input port domain Domain mOutputDomain; // output port domain std::string mCodingMediaType; // media type of the coded stream // standard MediaCodec to Codec 2.0 params mapping std::shared_ptr mStandardParams; std::set mSupportedIndices; ///< indices supported by the component std::set mSubscribedIndices; ///< indices to subscribe to size_t mSubscribedIndicesSize; ///< count of currently subscribed indices sp mInputFormat; sp mOutputFormat; bool mUsingSurface; ///< using input or output surface bool mBuffersBoundToCodec; ///< whether buffers are bound to codecs or not. std::shared_ptr mInputSurface; std::unique_ptr mISConfig; android_dataspace mInputSurfaceDataspace; /// the current configuration. Updated after configure() and based on configUpdate in /// onWorkDone std::map> mCurrentConfig; typedef std::function&)> LocalParamValidator; /// Parameter indices tracked in current config that are not supported by the component. /// these are provided so that optional parameters can remain in the current configuration. /// as such, these parameters have no dependencies. TODO: use C2InterfaceHelper for this. /// For now support a validation function. std::map mLocalParams; /// Vendor field name -> desc map. std::map> mVendorParams; std::set mLastConfig; /// Tunneled codecs bool mTunneled; sp mSidebandHandle; CCodecConfig(); /// initializes the members required to manage the format: descriptors, reflector, /// reflected param helper, domain, standard params, and subscribes to standard /// indices. status_t initialize( const std::shared_ptr &client, const std::shared_ptr &configurable); /** * Adds a locally maintained parameter. This is used for output configuration that can be * appended to the output buffers in case it is not supported by the component. */ template bool addLocalParam( const std::string &name, C2ParamDescriptor::attrib_t attrib = C2ParamDescriptor::IS_READ_ONLY, std::function&)> validator_ = std::function&)>()) { C2Param::Index index = T::PARAM_TYPE; if (mSupportedIndices.count(index) || mLocalParams.count(index)) { if (mSupportedIndices.count(index)) { mSubscribedIndices.emplace(index); } ALOGD("ignoring local param %s (%#x) as it is already %s", name.c_str(), (uint32_t)index, mSupportedIndices.count(index) ? "supported" : "local"); return false; // already supported by the component or already added } // wrap typed validator into untyped validator LocalParamValidator validator; if (validator_) { validator = [validator_](std::unique_ptr& p){ c2_status_t res = C2_BAD_VALUE; std::unique_ptr typed(static_cast(p.release())); // if parameter is correctly typed if (T::From(typed.get())) { res = validator_(typed); p.reset(typed.release()); } return res; }; } mLocalParams.emplace(index, validator); mParamUpdater->addStandardParam(name, attrib); return true; } /** * Adds a locally maintained parameter with a default value. */ template bool addLocalParam( std::unique_ptr default_, const std::string &name, C2ParamDescriptor::attrib_t attrib = C2ParamDescriptor::IS_READ_ONLY, std::function&)> validator_ = std::function&)>()) { if (addLocalParam(name, attrib, validator_)) { if (validator_) { c2_status_t err = validator_(default_); if (err != C2_OK) { ALOGD("default value for %s is invalid => %s", name.c_str(), asString(err)); return false; } } mCurrentConfig[T::PARAM_TYPE] = std::move(default_); return true; } return false; } template bool addLocalParam( T *default_, const std::string &name, C2ParamDescriptor::attrib_t attrib = C2ParamDescriptor::IS_READ_ONLY, std::function&)> validator_ = std::function&)>()) { return addLocalParam(std::unique_ptr(default_), name, attrib, validator_); } /// Applies configuration updates, and updates format in the specific domain. /// Returns true if formats were updated /// \param domain input/output bitmask bool updateConfiguration( std::vector> &configUpdate, Domain domain); /// Updates formats in the specific domain. Returns true if any of the formats have changed. /// \param domain input/output bitmask bool updateFormats(Domain domain); /** * Applies SDK configurations in a specific configuration domain. * Updates relevant input/output formats and subscribes to parameters specified in the * configuration. * \param domain config/setParam bitmask * \param blocking blocking mode to use with the component */ status_t getConfigUpdateFromSdkParams( std::shared_ptr configurable, const sp &sdkParams, Domain domain, c2_blocking_t blocking, std::vector> *configUpdate) const; /** * Applies a configuration update to the component. * Updates relevant input/output formats and subscribes to parameters specified in the * configuration. * \param blocking blocking mode to use with the component */ status_t setParameters( std::shared_ptr configurable, std::vector> &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 &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 &configurable, c2_blocking_t blocking); /** * Object that can be used to access configuration parameters and if they change. */ template struct Watcher { ~Watcher() = default; /// returns true if the value of this configuration has changed bool hasChanged() const { const C2Param *value = mParent->getConfigParameterValue(mIndex); if (value && mValue) { return *value != *mValue; } else { return value != mValue.get(); } } /// updates the current value and returns it std::shared_ptr update() { const C2Param *value = mParent->getConfigParameterValue(mIndex); if (value) { mValue = std::shared_ptr(T::From(C2Param::Copy(*value).release())); } return mValue; } private: Watcher(C2Param::Index index, const CCodecConfig *parent) : mParent(parent), mIndex(index) { update(); } friend struct CCodecConfig; const CCodecConfig *mParent; std::shared_ptr mValue; C2Param::Index mIndex; }; /** * Returns a watcher object for a parameter. */ template Watcher watch(C2Param::Index index = T::PARAM_TYPE) const { if (index.type() != T::PARAM_TYPE) { __builtin_trap(); } return Watcher(index, this); } /** * Queries supported parameters and put the keys to |names|. * TODO: currently this method queries vendor parameter keys only. * * \return OK if successful. * BAD_VALUE if |names| is nullptr. */ status_t querySupportedParameters(std::vector *names); /** * Describe the parameter with |name|, filling the information into |desc| * TODO: currently this method works only for vendor parameters. * * \return OK if successful. * BAD_VALUE if |desc| is nullptr. * NAME_NOT_FOUND if |name| is not a recognized parameter name. */ status_t describe(const std::string &name, CodecParameterDescriptor *desc); /** * Find corresponding indices for |names| and subscribe to them. */ status_t subscribeToVendorConfigUpdate( const std::shared_ptr &configurable, const std::vector &names, c2_blocking_t blocking = C2_DONT_BLOCK); /** * Find corresponding indices for |names| and unsubscribe from them. */ status_t unsubscribeFromVendorConfigUpdate( const std::shared_ptr &configurable, const std::vector &names, c2_blocking_t blocking = C2_DONT_BLOCK); private: /// initializes the standard MediaCodec to Codec 2.0 params mapping void initializeStandardParams(); /// 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 &configurable, const std::vector &indices, c2_blocking_t blocking = C2_DONT_BLOCK); /// Gets SDK format from codec 2.0 reflected configuration /// \param domain input/output bitmask sp getFormatForDomain( const ReflectedParamUpdater::Dict &reflected, Domain domain) const; /** * Converts a set of configuration parameters in an AMessage to a list of path-based Codec * 2.0 configuration parameters. * * \param domain config/setParam bitmask */ ReflectedParamUpdater::Dict getReflectedFormat( const sp &config, Domain domain) const; }; DEFINE_ENUM_OPERATORS(CCodecConfig::Domain) } // namespace android #endif // C_CODEC_H_