| /* |
| * 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_ |