|  | /* | 
|  | * 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 <map> | 
|  | #include <memory> | 
|  | #include <set> | 
|  | #include <vector> | 
|  |  | 
|  | #include <C2Component.h> | 
|  | #include <C2Config.h> | 
|  | #include <C2Debug.h> | 
|  |  | 
|  | #include <codec2/hidl/client.h> | 
|  | #include <utils/RefBase.h> | 
|  |  | 
|  | #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<std::shared_ptr<C2ParamDescriptor>> mParamDescs; | 
|  | std::shared_ptr<C2ParamReflector> mReflector; | 
|  |  | 
|  | std::shared_ptr<ReflectedParamUpdater> 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<StandardParams> mStandardParams; | 
|  |  | 
|  | std::set<C2Param::Index> mSupportedIndices; ///< indices supported by the component | 
|  | std::set<C2Param::Index> mSubscribedIndices; ///< indices to subscribe to | 
|  | size_t mSubscribedIndicesSize; ///< count of currently subscribed indices | 
|  |  | 
|  | sp<AMessage> mInputFormat; | 
|  | sp<AMessage> mOutputFormat; | 
|  |  | 
|  | bool mUsingSurface; ///< using input or output surface | 
|  | bool mBuffersBoundToCodec; ///< whether buffers are bound to codecs or not. | 
|  |  | 
|  | std::shared_ptr<InputSurfaceWrapper> mInputSurface; | 
|  | std::unique_ptr<InputSurfaceWrapper::Config> mISConfig; | 
|  | android_dataspace mInputSurfaceDataspace; | 
|  |  | 
|  | /// the current configuration. Updated after configure() and based on configUpdate in | 
|  | /// onWorkDone | 
|  | std::map<C2Param::Index, std::unique_ptr<C2Param>> mCurrentConfig; | 
|  |  | 
|  | typedef std::function<c2_status_t(std::unique_ptr<C2Param>&)> 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<C2Param::Index, LocalParamValidator> mLocalParams; | 
|  |  | 
|  | /// Vendor field name -> desc map. | 
|  | std::map<std::string, std::shared_ptr<C2ParamDescriptor>> mVendorParams; | 
|  |  | 
|  | std::set<std::string> mLastConfig; | 
|  |  | 
|  | /// Tunneled codecs | 
|  | bool mTunneled; | 
|  | sp<NativeHandle> mSidebandHandle; | 
|  |  | 
|  | bool mPushBlankBuffersOnStop; | 
|  |  | 
|  | 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<C2ParamReflector> &client, | 
|  | const std::shared_ptr<Codec2Client::Configurable> &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<typename T> | 
|  | bool addLocalParam( | 
|  | const std::string &name, | 
|  | C2ParamDescriptor::attrib_t attrib = C2ParamDescriptor::IS_READ_ONLY, | 
|  | std::function<c2_status_t(std::unique_ptr<T>&)> validator_ = | 
|  | std::function<c2_status_t(std::unique_ptr<T>&)>()) { | 
|  | 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<C2Param>& p){ | 
|  | c2_status_t res = C2_BAD_VALUE; | 
|  | std::unique_ptr<T> typed(static_cast<T*>(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<T>(name, attrib); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Adds a locally maintained parameter with a default value. | 
|  | */ | 
|  | template<typename T> | 
|  | bool addLocalParam( | 
|  | std::unique_ptr<T> default_, | 
|  | const std::string &name, | 
|  | C2ParamDescriptor::attrib_t attrib = C2ParamDescriptor::IS_READ_ONLY, | 
|  | std::function<c2_status_t(std::unique_ptr<T>&)> validator_ = | 
|  | std::function<c2_status_t(std::unique_ptr<T>&)>()) { | 
|  | if (addLocalParam<T>(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<typename T> | 
|  | bool addLocalParam( | 
|  | T *default_, const std::string &name, | 
|  | C2ParamDescriptor::attrib_t attrib = C2ParamDescriptor::IS_READ_ONLY, | 
|  | std::function<c2_status_t(std::unique_ptr<T>&)> validator_ = | 
|  | std::function<c2_status_t(std::unique_ptr<T>&)>()) { | 
|  | return addLocalParam(std::unique_ptr<T>(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<std::unique_ptr<C2Param>> &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<Codec2Client::Configurable> configurable, | 
|  | const sp<AMessage> &sdkParams, Domain domain, | 
|  | c2_blocking_t blocking, | 
|  | std::vector<std::unique_ptr<C2Param>> *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<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::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. | 
|  | */ | 
|  | template<typename T> | 
|  | 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<const T> update() { | 
|  | const C2Param *value = mParent->getConfigParameterValue(mIndex); | 
|  | if (value) { | 
|  | mValue = std::shared_ptr<const T>(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<const T> mValue; | 
|  | C2Param::Index mIndex; | 
|  | }; | 
|  |  | 
|  | /** | 
|  | * Returns a watcher object for a parameter. | 
|  | */ | 
|  | template<typename T> | 
|  | Watcher<T> watch(C2Param::Index index = T::PARAM_TYPE) const { | 
|  | if (index.type() != T::PARAM_TYPE) { | 
|  | __builtin_trap(); | 
|  | } | 
|  | return Watcher<T>(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<std::string> *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<Codec2Client::Configurable> &configurable, | 
|  | const std::vector<std::string> &names, | 
|  | c2_blocking_t blocking = C2_DONT_BLOCK); | 
|  |  | 
|  | /** | 
|  | * Find corresponding indices for |names| and unsubscribe from them. | 
|  | */ | 
|  | status_t unsubscribeFromVendorConfigUpdate( | 
|  | const std::shared_ptr<Codec2Client::Configurable> &configurable, | 
|  | const std::vector<std::string> &names, | 
|  | c2_blocking_t blocking = C2_DONT_BLOCK); | 
|  |  | 
|  | /// 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::Configurable> &configurable, | 
|  | const std::vector<C2Param::Index> &indices, | 
|  | c2_blocking_t blocking = C2_DONT_BLOCK); | 
|  |  | 
|  | private: | 
|  |  | 
|  | /// initializes the standard MediaCodec to Codec 2.0 params mapping | 
|  | void initializeStandardParams(); | 
|  |  | 
|  | /// Gets SDK format from codec 2.0 reflected configuration | 
|  | /// \param domain input/output bitmask | 
|  | 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 | 
|  | * 2.0 configuration parameters. | 
|  | * | 
|  | * \param domain config/setParam bitmask | 
|  | */ | 
|  | ReflectedParamUpdater::Dict getReflectedFormat( | 
|  | const sp<AMessage> &config, Domain domain) const; | 
|  | }; | 
|  |  | 
|  | DEFINE_ENUM_OPERATORS(CCodecConfig::Domain) | 
|  |  | 
|  | }  // namespace android | 
|  |  | 
|  | #endif  // C_CODEC_H_ |