1 /* 2 * Copyright (C) 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #ifndef C_CODEC_CONFIG_H_ 18 #define C_CODEC_CONFIG_H_ 19 20 #include <map> 21 #include <memory> 22 #include <set> 23 #include <vector> 24 25 #include <C2Component.h> 26 #include <C2Config.h> 27 #include <C2Debug.h> 28 29 #include <codec2/hidl/client.h> 30 #include <utils/RefBase.h> 31 32 #include "InputSurfaceWrapper.h" 33 #include "ReflectedParamUpdater.h" 34 35 namespace android { 36 37 struct AMessage; 38 struct CodecParameterDescriptor; 39 class NativeHandle; 40 struct StandardParams; 41 42 /** 43 * Struct managing the codec configuration for CCodec. 44 */ 45 struct CCodecConfig { 46 /** 47 * Domain consists of a bitmask divided into fields, and specifiers work by excluding other 48 * values in those domains. 49 * 50 * Component domains are composed by or-ing the individual IS_ constants, e.g. 51 * IS_DECODER | IS_AUDIO. 52 * 53 * Config specifiers are composed by or-ing the individual mask constants, and 54 * and-ing these groups: e.g. (DECODER | ENCODER) & AUDIO. 55 * 56 * The naming of these constants was to limit the length of mask names as these are used more 57 * commonly as masks. 58 */ 59 enum Domain : uint32_t { 60 // component domain (domain & kind) 61 GUARD_BIT = (1 << 1), ///< this is to prevent against accidental && or || usage 62 IS_AUDIO = (1 << 2), ///< for audio codecs 63 IS_VIDEO = (1 << 3), ///< for video codecs 64 IS_IMAGE = (1 << 4), ///< for image codecs 65 OTHER_DOMAIN = (1 << 5), ///< for other domains 66 67 IS_ENCODER = (1 << 6), ///< for encoders 68 IS_DECODER = (1 << 7), ///< for decoders 69 OTHER_KIND = (1 << 8), ///< for other domains 70 71 // config domain 72 IS_PARAM = (1 << 9), ///< for setParameter 73 IS_CONFIG = (1 << 10), ///< for configure 74 IS_READ = (1 << 11), ///< for getFormat 75 76 // port domain 77 IS_INPUT = (1 << 12), ///< for input port (getFormat) 78 IS_OUTPUT = (1 << 13), ///< for output port (getFormat) 79 IS_RAW = (1 << 14), ///< for raw port (input-encoder, output-decoder) 80 IS_CODED = (1 << 15), ///< for coded port (input-decoder, output-encoder) 81 82 ALL = ~0U, 83 NONE = 0, 84 85 AUDIO = ~(IS_IMAGE | IS_VIDEO | OTHER_DOMAIN), 86 VIDEO = ~(IS_AUDIO | IS_IMAGE | OTHER_DOMAIN), 87 IMAGE = ~(IS_AUDIO | IS_VIDEO | OTHER_DOMAIN), 88 89 DECODER = ~(IS_ENCODER | OTHER_KIND), 90 ENCODER = ~(IS_DECODER | OTHER_KIND), 91 92 PARAM = ~(IS_CONFIG | IS_READ), 93 CONFIG = ~(IS_PARAM | IS_READ), 94 READ = ~(IS_CONFIG | IS_PARAM), 95 96 INPUT = ~(IS_OUTPUT | IS_RAW | IS_CODED), 97 OUTPUT = ~(IS_INPUT | IS_RAW | IS_CODED), 98 RAW = ~(IS_INPUT | IS_OUTPUT | IS_CODED), 99 CODED = ~(IS_INPUT | IS_RAW | IS_OUTPUT), 100 }; 101 102 // things required to manage formats 103 std::vector<std::shared_ptr<C2ParamDescriptor>> mParamDescs; 104 std::shared_ptr<C2ParamReflector> mReflector; 105 106 std::shared_ptr<ReflectedParamUpdater> mParamUpdater; 107 108 Domain mDomain; // component domain 109 Domain mInputDomain; // input port domain 110 Domain mOutputDomain; // output port domain 111 std::string mCodingMediaType; // media type of the coded stream 112 113 // standard MediaCodec to Codec 2.0 params mapping 114 std::shared_ptr<StandardParams> mStandardParams; 115 116 std::set<C2Param::Index> mSupportedIndices; ///< indices supported by the component 117 std::set<C2Param::Index> mSubscribedIndices; ///< indices to subscribe to 118 size_t mSubscribedIndicesSize; ///< count of currently subscribed indices 119 120 sp<AMessage> mInputFormat; 121 sp<AMessage> mOutputFormat; 122 123 bool mUsingSurface; ///< using input or output surface 124 bool mBuffersBoundToCodec; ///< whether buffers are bound to codecs or not. 125 126 std::shared_ptr<InputSurfaceWrapper> mInputSurface; 127 std::unique_ptr<InputSurfaceWrapper::Config> mISConfig; 128 android_dataspace mInputSurfaceDataspace; 129 130 /// the current configuration. Updated after configure() and based on configUpdate in 131 /// onWorkDone 132 std::map<C2Param::Index, std::unique_ptr<C2Param>> mCurrentConfig; 133 134 typedef std::function<c2_status_t(std::unique_ptr<C2Param>&)> LocalParamValidator; 135 136 /// Parameter indices tracked in current config that are not supported by the component. 137 /// these are provided so that optional parameters can remain in the current configuration. 138 /// as such, these parameters have no dependencies. TODO: use C2InterfaceHelper for this. 139 /// For now support a validation function. 140 std::map<C2Param::Index, LocalParamValidator> mLocalParams; 141 142 /// Vendor field name -> desc map. 143 std::map<std::string, std::shared_ptr<C2ParamDescriptor>> mVendorParams; 144 145 std::set<std::string> mLastConfig; 146 147 /// Tunneled codecs 148 bool mTunneled; 149 sp<NativeHandle> mSidebandHandle; 150 151 CCodecConfig(); 152 153 /// initializes the members required to manage the format: descriptors, reflector, 154 /// reflected param helper, domain, standard params, and subscribes to standard 155 /// indices. 156 status_t initialize( 157 const std::shared_ptr<C2ParamReflector> &client, 158 const std::shared_ptr<Codec2Client::Configurable> &configurable); 159 160 /** 161 * Adds a locally maintained parameter. This is used for output configuration that can be 162 * appended to the output buffers in case it is not supported by the component. 163 */ 164 template<typename T> 165 bool addLocalParam( 166 const std::string &name, 167 C2ParamDescriptor::attrib_t attrib = C2ParamDescriptor::IS_READ_ONLY, 168 std::function<c2_status_t(std::unique_ptr<T>&)> validator_ = 169 std::function<c2_status_t(std::unique_ptr<T>&)>()) { 170 C2Param::Index index = T::PARAM_TYPE; 171 if (mSupportedIndices.count(index) || mLocalParams.count(index)) { 172 if (mSupportedIndices.count(index)) { 173 mSubscribedIndices.emplace(index); 174 } 175 ALOGD("ignoring local param %s (%#x) as it is already %s", 176 name.c_str(), (uint32_t)index, mSupportedIndices.count(index) ? "supported" : "local"); 177 return false; // already supported by the component or already added 178 } 179 180 // wrap typed validator into untyped validator 181 LocalParamValidator validator; 182 if (validator_) { 183 validator = [validator_](std::unique_ptr<C2Param>& p){ 184 c2_status_t res = C2_BAD_VALUE; 185 std::unique_ptr<T> typed(static_cast<T*>(p.release())); 186 // if parameter is correctly typed 187 if (T::From(typed.get())) { 188 res = validator_(typed); 189 p.reset(typed.release()); 190 } 191 return res; 192 }; 193 } 194 195 mLocalParams.emplace(index, validator); 196 mParamUpdater->addStandardParam<T>(name, attrib); 197 return true; 198 } 199 200 /** 201 * Adds a locally maintained parameter with a default value. 202 */ 203 template<typename T> 204 bool addLocalParam( 205 std::unique_ptr<T> default_, 206 const std::string &name, 207 C2ParamDescriptor::attrib_t attrib = C2ParamDescriptor::IS_READ_ONLY, 208 std::function<c2_status_t(std::unique_ptr<T>&)> validator_ = 209 std::function<c2_status_t(std::unique_ptr<T>&)>()) { 210 if (addLocalParam<T>(name, attrib, validator_)) { 211 if (validator_) { 212 c2_status_t err = validator_(default_); 213 if (err != C2_OK) { 214 ALOGD("default value for %s is invalid => %s", name.c_str(), asString(err)); 215 return false; 216 } 217 } 218 mCurrentConfig[T::PARAM_TYPE] = std::move(default_); 219 return true; 220 } 221 return false; 222 } 223 224 template<typename T> 225 bool addLocalParam( 226 T *default_, const std::string &name, 227 C2ParamDescriptor::attrib_t attrib = C2ParamDescriptor::IS_READ_ONLY, 228 std::function<c2_status_t(std::unique_ptr<T>&)> validator_ = 229 std::function<c2_status_t(std::unique_ptr<T>&)>()) { 230 return addLocalParam(std::unique_ptr<T>(default_), name, attrib, validator_); 231 } 232 233 /// Applies configuration updates, and updates format in the specific domain. 234 /// Returns true if formats were updated 235 /// \param domain input/output bitmask 236 bool updateConfiguration( 237 std::vector<std::unique_ptr<C2Param>> &configUpdate, Domain domain); 238 239 /// Updates formats in the specific domain. Returns true if any of the formats have changed. 240 /// \param domain input/output bitmask 241 bool updateFormats(Domain domain); 242 243 /** 244 * Applies SDK configurations in a specific configuration domain. 245 * Updates relevant input/output formats and subscribes to parameters specified in the 246 * configuration. 247 * \param domain config/setParam bitmask 248 * \param blocking blocking mode to use with the component 249 */ 250 status_t getConfigUpdateFromSdkParams( 251 std::shared_ptr<Codec2Client::Configurable> configurable, 252 const sp<AMessage> &sdkParams, Domain domain, 253 c2_blocking_t blocking, 254 std::vector<std::unique_ptr<C2Param>> *configUpdate) const; 255 256 /** 257 * Applies a configuration update to the component. 258 * Updates relevant input/output formats and subscribes to parameters specified in the 259 * configuration. 260 * \param blocking blocking mode to use with the component 261 */ 262 status_t setParameters( 263 std::shared_ptr<Codec2Client::Configurable> configurable, 264 std::vector<std::unique_ptr<C2Param>> &configUpdate, 265 c2_blocking_t blocking); 266 267 /// Queries subscribed indices (which contains all SDK-exposed values) and updates 268 /// input/output formats. 269 status_t queryConfiguration( 270 const std::shared_ptr<Codec2Client::Configurable> &configurable); 271 272 /// Queries a configuration parameter value. Returns nullptr if the parameter is not 273 /// part of the current configuration 274 const C2Param *getConfigParameterValue(C2Param::Index index) const; 275 276 /// Subscribe to all vendor parameters. 277 status_t subscribeToAllVendorParams( 278 const std::shared_ptr<Codec2Client::Configurable> &configurable, 279 c2_blocking_t blocking); 280 281 /** 282 * Object that can be used to access configuration parameters and if they change. 283 */ 284 template<typename T> 285 struct Watcher { 286 ~Watcher() = default; 287 288 /// returns true if the value of this configuration has changed hasChangedCCodecConfig::Watcher289 bool hasChanged() const { 290 const C2Param *value = mParent->getConfigParameterValue(mIndex); 291 if (value && mValue) { 292 return *value != *mValue; 293 } else { 294 return value != mValue.get(); 295 } 296 } 297 298 /// updates the current value and returns it updateCCodecConfig::Watcher299 std::shared_ptr<const T> update() { 300 const C2Param *value = mParent->getConfigParameterValue(mIndex); 301 if (value) { 302 mValue = std::shared_ptr<const T>(T::From(C2Param::Copy(*value).release())); 303 } 304 return mValue; 305 } 306 307 private: WatcherCCodecConfig::Watcher308 Watcher(C2Param::Index index, const CCodecConfig *parent) 309 : mParent(parent), mIndex(index) { 310 update(); 311 } 312 313 friend struct CCodecConfig; 314 315 const CCodecConfig *mParent; 316 std::shared_ptr<const T> mValue; 317 C2Param::Index mIndex; 318 }; 319 320 /** 321 * Returns a watcher object for a parameter. 322 */ 323 template<typename T> 324 Watcher<T> watch(C2Param::Index index = T::PARAM_TYPE) const { 325 if (index.type() != T::PARAM_TYPE) { 326 __builtin_trap(); 327 } 328 return Watcher<T>(index, this); 329 } 330 331 /** 332 * Queries supported parameters and put the keys to |names|. 333 * TODO: currently this method queries vendor parameter keys only. 334 * 335 * \return OK if successful. 336 * BAD_VALUE if |names| is nullptr. 337 */ 338 status_t querySupportedParameters(std::vector<std::string> *names); 339 340 /** 341 * Describe the parameter with |name|, filling the information into |desc| 342 * TODO: currently this method works only for vendor parameters. 343 * 344 * \return OK if successful. 345 * BAD_VALUE if |desc| is nullptr. 346 * NAME_NOT_FOUND if |name| is not a recognized parameter name. 347 */ 348 status_t describe(const std::string &name, CodecParameterDescriptor *desc); 349 350 /** 351 * Find corresponding indices for |names| and subscribe to them. 352 */ 353 status_t subscribeToVendorConfigUpdate( 354 const std::shared_ptr<Codec2Client::Configurable> &configurable, 355 const std::vector<std::string> &names, 356 c2_blocking_t blocking = C2_DONT_BLOCK); 357 358 /** 359 * Find corresponding indices for |names| and unsubscribe from them. 360 */ 361 status_t unsubscribeFromVendorConfigUpdate( 362 const std::shared_ptr<Codec2Client::Configurable> &configurable, 363 const std::vector<std::string> &names, 364 c2_blocking_t blocking = C2_DONT_BLOCK); 365 366 private: 367 368 /// initializes the standard MediaCodec to Codec 2.0 params mapping 369 void initializeStandardParams(); 370 371 /// Adds indices to the subscribed indices, and updated subscription to component 372 /// \param blocking blocking mode to use with the component 373 status_t subscribeToConfigUpdate( 374 const std::shared_ptr<Codec2Client::Configurable> &configurable, 375 const std::vector<C2Param::Index> &indices, 376 c2_blocking_t blocking = C2_DONT_BLOCK); 377 378 /// Gets SDK format from codec 2.0 reflected configuration 379 /// \param domain input/output bitmask 380 sp<AMessage> getFormatForDomain( 381 const ReflectedParamUpdater::Dict &reflected, 382 Domain domain) const; 383 384 /** 385 * Converts a set of configuration parameters in an AMessage to a list of path-based Codec 386 * 2.0 configuration parameters. 387 * 388 * \param domain config/setParam bitmask 389 */ 390 ReflectedParamUpdater::Dict getReflectedFormat( 391 const sp<AMessage> &config, Domain domain) const; 392 }; 393 394 DEFINE_ENUM_OPERATORS(CCodecConfig::Domain) 395 396 } // namespace android 397 398 #endif // C_CODEC_H_ 399 400