• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 //#define LOG_NDEBUG 0
18 #define LOG_TAG "CCodecConfig"
19 
20 #include <initializer_list>
21 
22 #include <cutils/properties.h>
23 #include <log/log.h>
24 #include <utils/NativeHandle.h>
25 
26 #include <android-base/properties.h>
27 
28 #include <C2Component.h>
29 #include <C2Param.h>
30 #include <util/C2InterfaceHelper.h>
31 
32 #include <media/stagefright/CodecBase.h>
33 #include <media/stagefright/MediaCodecConstants.h>
34 
35 #include "CCodecConfig.h"
36 #include "Codec2Mapper.h"
37 
38 #define DRC_DEFAULT_MOBILE_REF_LEVEL 64  /* 64*-0.25dB = -16 dB below full scale for mobile conf */
39 #define DRC_DEFAULT_MOBILE_DRC_CUT   127 /* maximum compression of dynamic range for mobile conf */
40 #define DRC_DEFAULT_MOBILE_DRC_BOOST 127 /* maximum compression of dynamic range for mobile conf */
41 #define DRC_DEFAULT_MOBILE_DRC_HEAVY 1   /* switch for heavy compression for mobile conf */
42 #define DRC_DEFAULT_MOBILE_DRC_EFFECT 3  /* MPEG-D DRC effect type; 3 => Limited playback range */
43 #define DRC_DEFAULT_MOBILE_DRC_ALBUM 0   /* MPEG-D DRC album mode; 0 => album mode is disabled, 1 => album mode is enabled */
44 #define DRC_DEFAULT_MOBILE_OUTPUT_LOUDNESS -1 /* decoder output loudness; -1 => the value is unknown, otherwise dB step value (e.g. 64 for -16 dB) */
45 #define DRC_DEFAULT_MOBILE_ENC_LEVEL (-1) /* encoder target level; -1 => the value is unknown, otherwise dB step value (e.g. 64 for -16 dB) */
46 // names of properties that can be used to override the default DRC settings
47 #define PROP_DRC_OVERRIDE_REF_LEVEL  "aac_drc_reference_level"
48 #define PROP_DRC_OVERRIDE_CUT        "aac_drc_cut"
49 #define PROP_DRC_OVERRIDE_BOOST      "aac_drc_boost"
50 #define PROP_DRC_OVERRIDE_HEAVY      "aac_drc_heavy"
51 #define PROP_DRC_OVERRIDE_ENC_LEVEL  "aac_drc_enc_target_level"
52 #define PROP_DRC_OVERRIDE_EFFECT     "ro.aac_drc_effect_type"
53 
54 namespace android {
55 
56 // CCodecConfig
57 
58 namespace {
59 
C2ValueToMessageItem(const C2Value & value,AMessage::ItemData & item)60 void C2ValueToMessageItem(const C2Value &value, AMessage::ItemData &item) {
61     int32_t int32Value;
62     uint32_t uint32Value;
63     int64_t int64Value;
64     uint64_t uint64Value;
65     float floatValue;
66     if (value.get(&int32Value)) {
67         item.set(int32Value);
68     } else if (value.get(&uint32Value) && uint32Value <= uint32_t(INT32_MAX)) {
69         // SDK does not support unsigned values
70         item.set((int32_t)uint32Value);
71     } else if (value.get(&int64Value)) {
72         item.set(int64Value);
73     } else if (value.get(&uint64Value) && uint64Value <= uint64_t(INT64_MAX)) {
74         // SDK does not support unsigned values
75         item.set((int64_t)uint64Value);
76     } else if (value.get(&floatValue)) {
77         item.set(floatValue);
78     }
79 }
80 
81 /**
82  * mapping between SDK and Codec 2.0 configurations.
83  */
84 struct ConfigMapper {
85     /**
86      * Value mapper (C2Value => C2Value)
87      */
88     typedef std::function<C2Value(C2Value)> Mapper;
89 
90     /// shorthand
91     typedef CCodecConfig::Domain Domain;
92 
ConfigMapperandroid::__anone0eef06e0111::ConfigMapper93     ConfigMapper(std::string mediaKey, C2String c2struct, C2String c2field)
94         : mDomain(Domain::ALL), mMediaKey(mediaKey), mStruct(c2struct), mField(c2field) { }
95 
96     /// Limits this parameter to the given domain
limitToandroid::__anone0eef06e0111::ConfigMapper97     ConfigMapper &limitTo(uint32_t domain) {
98         C2_CHECK(domain & Domain::GUARD_BIT);
99         mDomain = Domain(mDomain & domain);
100         return *this;
101     }
102 
103     /// Adds SDK => Codec 2.0 mapper (should not be in the SDK format)
withMapperandroid::__anone0eef06e0111::ConfigMapper104     ConfigMapper &withMapper(Mapper mapper) {
105         C2_CHECK(!mMapper);
106         C2_CHECK(!mReverse);
107         mMapper = mapper;
108         return *this;
109     }
110 
111     /// Adds SDK <=> Codec 2.0 value mappers
withMappersandroid::__anone0eef06e0111::ConfigMapper112     ConfigMapper &withMappers(Mapper mapper, Mapper reverse) {
113         C2_CHECK(!mMapper);
114         C2_CHECK(!mReverse);
115         mMapper = mapper;
116         mReverse = reverse;
117         return *this;
118     }
119 
120     /// Adds SDK <=> Codec 2.0 value mappers based on C2Mapper
121     template<typename C2Type, typename SdkType=int32_t>
withC2Mappersandroid::__anone0eef06e0111::ConfigMapper122     ConfigMapper &withC2Mappers() {
123         C2_CHECK(!mMapper);
124         C2_CHECK(!mReverse);
125         mMapper = [](C2Value v) -> C2Value {
126             SdkType sdkValue;
127             C2Type c2Value;
128             if (v.get(&sdkValue) && C2Mapper::map(sdkValue, &c2Value)) {
129                 return c2Value;
130             }
131             return C2Value();
132         };
133         mReverse = [](C2Value v) -> C2Value {
134             SdkType sdkValue;
135             C2Type c2Value;
136             using C2ValueType=typename _c2_reduce_enum_to_underlying_type<C2Type>::type;
137             if (v.get((C2ValueType*)&c2Value) && C2Mapper::map(c2Value, &sdkValue)) {
138                 return sdkValue;
139             }
140             return C2Value();
141         };
142         return *this;
143     }
144 
145     /// Maps from SDK values in an AMessage to a suitable C2Value.
mapFromMessageandroid::__anone0eef06e0111::ConfigMapper146     C2Value mapFromMessage(const AMessage::ItemData &item) const {
147         C2Value value;
148         int32_t int32Value;
149         int64_t int64Value;
150         float floatValue;
151         double doubleValue;
152         if (item.find(&int32Value)) {
153             value = int32Value;
154         } else if (item.find(&int64Value)) {
155             value = int64Value;
156         } else if (item.find(&floatValue)) {
157             value = floatValue;
158         } else if (item.find(&doubleValue)) {
159             value = (float)doubleValue;
160         }
161         if (value.type() != C2Value::NO_INIT && mMapper) {
162             value = mMapper(value);
163         }
164         return value;
165     }
166 
167     /// Maps from a C2Value to an SDK value in an AMessage.
mapToMessageandroid::__anone0eef06e0111::ConfigMapper168     AMessage::ItemData mapToMessage(C2Value value) const {
169         AMessage::ItemData item;
170         if (value.type() != C2Value::NO_INIT && mReverse) {
171             value = mReverse(value);
172         }
173         C2ValueToMessageItem(value, item);
174         return item;
175     }
176 
domainandroid::__anone0eef06e0111::ConfigMapper177     Domain domain() const { return mDomain; }
mediaKeyandroid::__anone0eef06e0111::ConfigMapper178     std::string mediaKey() const { return mMediaKey; }
pathandroid::__anone0eef06e0111::ConfigMapper179     std::string path() const { return mField.size() ? mStruct + '.' + mField : mStruct; }
mapperandroid::__anone0eef06e0111::ConfigMapper180     Mapper mapper() const { return mMapper; }
reverseandroid::__anone0eef06e0111::ConfigMapper181     Mapper reverse() const { return mReverse; }
182 
183 private:
184     Domain mDomain;         ///< parameter domain (mask) containing port, kind and config domains
185     std::string mMediaKey;  ///< SDK key
186     C2String mStruct;       ///< Codec 2.0 struct name
187     C2String mField;        ///< Codec 2.0 field name
188     Mapper mMapper;         ///< optional SDK => Codec 2.0 value mapper
189     Mapper mReverse;        ///< optional Codec 2.0 => SDK value mapper
190 };
191 
192 template <typename PORT, typename STREAM>
QueryMediaTypeImpl(const std::shared_ptr<Codec2Client::Configurable> & configurable)193 AString QueryMediaTypeImpl(
194         const std::shared_ptr<Codec2Client::Configurable> &configurable) {
195     AString mediaType;
196     std::vector<std::unique_ptr<C2Param>> queried;
197     c2_status_t c2err = configurable->query(
198             {}, { PORT::PARAM_TYPE, STREAM::PARAM_TYPE }, C2_DONT_BLOCK, &queried);
199     if (c2err != C2_OK && queried.size() == 0) {
200         ALOGD("Query media type failed => %s", asString(c2err));
201     } else {
202         PORT *portMediaType =
203             PORT::From(queried[0].get());
204         if (portMediaType) {
205             mediaType = AString(
206                     portMediaType->m.value,
207                     strnlen(portMediaType->m.value, portMediaType->flexCount()));
208         } else {
209             STREAM *streamMediaType = STREAM::From(queried[0].get());
210             if (streamMediaType) {
211                 mediaType = AString(
212                         streamMediaType->m.value,
213                         strnlen(streamMediaType->m.value, streamMediaType->flexCount()));
214             }
215         }
216         ALOGD("read media type: %s", mediaType.c_str());
217     }
218     return mediaType;
219 }
220 
QueryMediaType(bool input,const std::shared_ptr<Codec2Client::Configurable> & configurable)221 AString QueryMediaType(
222         bool input, const std::shared_ptr<Codec2Client::Configurable> &configurable) {
223     typedef C2PortMediaTypeSetting P;
224     typedef C2StreamMediaTypeSetting S;
225     if (input) {
226         return QueryMediaTypeImpl<P::input, S::input>(configurable);
227     } else {
228         return QueryMediaTypeImpl<P::output, S::output>(configurable);
229     }
230 }
231 
232 }  // namespace
233 
234 /**
235  * Set of standard parameters used by CCodec that are exposed to MediaCodec.
236  */
237 struct StandardParams {
238     typedef CCodecConfig::Domain Domain;
239 
240     // standard (MediaCodec) params are keyed by media format key
241     typedef std::string SdkKey;
242 
243     /// used to return reference to no config mappers in getConfigMappersForSdkKey
244     static const std::vector<ConfigMapper> NO_MAPPERS;
245 
246     /// Returns Codec 2.0 equivalent parameters for an SDK format key.
getConfigMappersForSdkKeyandroid::StandardParams247     const std::vector<ConfigMapper> &getConfigMappersForSdkKey(std::string key) const {
248         auto it = mConfigMappers.find(key);
249         if (it == mConfigMappers.end()) {
250             if (mComplained.count(key) == 0) {
251                 ALOGD("no c2 equivalents for %s", key.c_str());
252                 mComplained.insert(key);
253             }
254             return NO_MAPPERS;
255         }
256         ALOGV("found %zu eqs for %s", it->second.size(), key.c_str());
257         return it->second;
258     }
259 
260     /**
261      * Adds a SDK <=> Codec 2.0 parameter mapping. Multiple Codec 2.0 parameters may map to a
262      * single SDK key, in which case they shall be ordered from least authoritative to most
263      * authoritative. When constructing SDK formats, the last mapped Codec 2.0 parameter that
264      * is supported by the component will determine the exposed value. (TODO: perhaps restrict this
265      * by domain.)
266      */
addandroid::StandardParams267     void add(const ConfigMapper &cm) {
268         auto it = mConfigMappers.find(cm.mediaKey());
269         ALOGV("%c%c%c%c %c%c%c %04x %9s %s => %s",
270               ((cm.domain() & Domain::IS_INPUT) ? 'I' : ' '),
271               ((cm.domain() & Domain::IS_OUTPUT) ? 'O' : ' '),
272               ((cm.domain() & Domain::IS_CODED) ? 'C' : ' '),
273               ((cm.domain() & Domain::IS_RAW) ? 'R' : ' '),
274               ((cm.domain() & Domain::IS_CONFIG) ? 'c' : ' '),
275               ((cm.domain() & Domain::IS_PARAM) ? 'p' : ' '),
276               ((cm.domain() & Domain::IS_READ) ? 'r' : ' '),
277               cm.domain(),
278               it == mConfigMappers.end() ? "adding" : "extending",
279               cm.mediaKey().c_str(), cm.path().c_str());
280         if (it == mConfigMappers.end()) {
281             std::vector<ConfigMapper> eqs = { cm };
282             mConfigMappers.emplace(cm.mediaKey(), eqs);
283         } else {
284             it->second.push_back(cm);
285         }
286     }
287 
288     /**
289      * Returns all paths for a specific domain.
290      *
291      * \param any maximum domain mask. Returned parameters must match at least one of the domains
292      *            in the mask.
293      * \param all minimum domain mask. Returned parameters must match all of the domains in the
294      *            mask. This is restricted to the bits of the maximum mask.
295      */
getPathsForDomainandroid::StandardParams296     std::vector<std::string> getPathsForDomain(
297             Domain any, Domain all = Domain::ALL) const {
298         std::vector<std::string> res;
299         for (const auto &[key, mappers] : mConfigMappers) {
300             for (const ConfigMapper &cm : mappers) {
301                 ALOGV("filtering %s %x %x %x %x", cm.path().c_str(), cm.domain(), any,
302                         (cm.domain() & any), (cm.domain() & any & all));
303                 if ((cm.domain() & any) && ((cm.domain() & any & all) == (any & all))) {
304                     res.push_back(cm.path());
305                 }
306             }
307         }
308         return res;
309     }
310 
311     /**
312      * Returns SDK <=> Codec 2.0 mappings.
313      *
314      * TODO: replace these with better methods as this exposes the inner structure.
315      */
getKeysandroid::StandardParams316     const std::map<SdkKey, std::vector<ConfigMapper>> getKeys() const {
317         return mConfigMappers;
318     }
319 
320 private:
321     std::map<SdkKey, std::vector<ConfigMapper>> mConfigMappers;
322     mutable std::set<std::string> mComplained;
323 };
324 
325 const std::vector<ConfigMapper> StandardParams::NO_MAPPERS;
326 
327 
CCodecConfig()328 CCodecConfig::CCodecConfig()
329     : mInputFormat(new AMessage),
330       mOutputFormat(new AMessage),
331       mUsingSurface(false),
332       mTunneled(false),
333       mPushBlankBuffersOnStop(false) { }
334 
initializeStandardParams()335 void CCodecConfig::initializeStandardParams() {
336     typedef Domain D;
337     mStandardParams = std::make_shared<StandardParams>();
338     std::function<void(const ConfigMapper &)> add =
339         [params = mStandardParams](const ConfigMapper &cm) {
340             params->add(cm);
341     };
342     std::function<void(const ConfigMapper &)> deprecated = add;
343 
344     // allow int32 or float SDK values and represent them as float
345     ConfigMapper::Mapper makeFloat = [](C2Value v) -> C2Value {
346         // convert from i32 to float
347         int32_t i32Value;
348         float fpValue;
349         if (v.get(&i32Value)) {
350             return (float)i32Value;
351         } else if (v.get(&fpValue)) {
352             return fpValue;
353         }
354         return C2Value();
355     };
356 
357     ConfigMapper::Mapper negate = [](C2Value v) -> C2Value {
358         int32_t value;
359         if (v.get(&value)) {
360             return -value;
361         }
362         return C2Value();
363     };
364 
365     add(ConfigMapper(KEY_MIME,     C2_PARAMKEY_INPUT_MEDIA_TYPE,    "value")
366         .limitTo(D::INPUT & D::READ));
367     add(ConfigMapper(KEY_MIME,     C2_PARAMKEY_OUTPUT_MEDIA_TYPE,   "value")
368         .limitTo(D::OUTPUT & D::READ));
369 
370     add(ConfigMapper(KEY_BIT_RATE, C2_PARAMKEY_BITRATE, "value")
371         .limitTo(D::ENCODER & D::CODED));
372     // Some audio decoders require bitrate information to be set
373     add(ConfigMapper(KEY_BIT_RATE, C2_PARAMKEY_BITRATE, "value")
374         .limitTo(D::AUDIO & D::DECODER & D::CODED));
375     // we also need to put the bitrate in the max bitrate field
376     add(ConfigMapper(KEY_MAX_BIT_RATE, C2_PARAMKEY_BITRATE, "value")
377         .limitTo(D::ENCODER & D::READ & D::OUTPUT));
378     add(ConfigMapper(PARAMETER_KEY_VIDEO_BITRATE, C2_PARAMKEY_BITRATE, "value")
379         .limitTo(D::ENCODER & D::VIDEO & D::PARAM));
380     add(ConfigMapper(KEY_BITRATE_MODE, C2_PARAMKEY_BITRATE_MODE, "value")
381         .limitTo(D::ENCODER & D::CODED)
382         .withC2Mappers<C2Config::bitrate_mode_t>());
383     // remove when codecs switch to PARAMKEY and new modes
384     deprecated(ConfigMapper(KEY_BITRATE_MODE, "coded.bitrate-mode", "value")
385                .limitTo(D::ENCODER));
386     add(ConfigMapper(KEY_FRAME_RATE, C2_PARAMKEY_FRAME_RATE, "value")
387         .limitTo(D::VIDEO)
388         .withMappers(makeFloat, [](C2Value v) -> C2Value {
389             // read back always as int
390             float value;
391             if (v.get(&value)) {
392                 return (int32_t)value;
393             }
394             return C2Value();
395         }));
396 
397     add(ConfigMapper(KEY_MAX_INPUT_SIZE, C2_PARAMKEY_INPUT_MAX_BUFFER_SIZE, "value")
398         .limitTo(D::INPUT));
399     // remove when codecs switch to PARAMKEY
400     deprecated(ConfigMapper(KEY_MAX_INPUT_SIZE, "coded.max-frame-size", "value")
401                .limitTo(D::INPUT));
402 
403     // Rotation
404     // Note: SDK rotation is clock-wise, while C2 rotation is counter-clock-wise
405     add(ConfigMapper(KEY_ROTATION, C2_PARAMKEY_VUI_ROTATION, "value")
406         .limitTo((D::VIDEO | D::IMAGE) & D::CODED)
407         .withMappers(negate, negate));
408     add(ConfigMapper(KEY_ROTATION, C2_PARAMKEY_ROTATION, "value")
409         .limitTo((D::VIDEO | D::IMAGE) & D::RAW)
410         .withMappers(negate, negate));
411 
412     // android 'video-scaling'
413     add(ConfigMapper("android._video-scaling", C2_PARAMKEY_SURFACE_SCALING_MODE, "value")
414         .limitTo(D::VIDEO & D::DECODER & D::RAW));
415 
416     // Color Aspects
417     //
418     // configure default for decoders
419     add(ConfigMapper(KEY_COLOR_RANGE,       C2_PARAMKEY_DEFAULT_COLOR_ASPECTS,   "range")
420         .limitTo((D::VIDEO | D::IMAGE) & D::DECODER  & D::CODED & (D::CONFIG | D::PARAM))
421         .withC2Mappers<C2Color::range_t>());
422     add(ConfigMapper(KEY_COLOR_TRANSFER,    C2_PARAMKEY_DEFAULT_COLOR_ASPECTS,   "transfer")
423         .limitTo((D::VIDEO | D::IMAGE) & D::DECODER  & D::CODED & (D::CONFIG | D::PARAM))
424         .withC2Mappers<C2Color::transfer_t>());
425     add(ConfigMapper("color-primaries",     C2_PARAMKEY_DEFAULT_COLOR_ASPECTS,   "primaries")
426         .limitTo((D::VIDEO | D::IMAGE) & D::DECODER  & D::CODED & (D::CONFIG | D::PARAM)));
427     add(ConfigMapper("color-matrix",        C2_PARAMKEY_DEFAULT_COLOR_ASPECTS,   "matrix")
428         .limitTo((D::VIDEO | D::IMAGE) & D::DECODER  & D::CODED & (D::CONFIG | D::PARAM)));
429 
430     // read back default for decoders. This is needed in case the component does not support
431     // color aspects. In that case, these values get copied to color-* keys.
432     // TRICKY: We read these values at raw port, since that's where we want to read these.
433     add(ConfigMapper("default-color-range",     C2_PARAMKEY_DEFAULT_COLOR_ASPECTS,   "range")
434         .limitTo((D::VIDEO | D::IMAGE) & D::DECODER  & D::RAW & D::READ)
435         .withC2Mappers<C2Color::range_t>());
436     add(ConfigMapper("default-color-transfer",  C2_PARAMKEY_DEFAULT_COLOR_ASPECTS,   "transfer")
437         .limitTo((D::VIDEO | D::IMAGE) & D::DECODER  & D::RAW & D::READ)
438         .withC2Mappers<C2Color::transfer_t>());
439     add(ConfigMapper("default-color-primaries", C2_PARAMKEY_DEFAULT_COLOR_ASPECTS,   "primaries")
440         .limitTo((D::VIDEO | D::IMAGE) & D::DECODER  & D::RAW & D::READ));
441     add(ConfigMapper("default-color-matrix",    C2_PARAMKEY_DEFAULT_COLOR_ASPECTS,   "matrix")
442         .limitTo((D::VIDEO | D::IMAGE) & D::DECODER  & D::RAW & D::READ));
443 
444     // read back final for decoder output (also, configure final aspects as well. This should be
445     // overwritten based on coded/default values if component supports color aspects, but is used
446     // as final values if component does not support aspects at all)
447     add(ConfigMapper(KEY_COLOR_RANGE,       C2_PARAMKEY_COLOR_ASPECTS,   "range")
448         .limitTo((D::VIDEO | D::IMAGE) & D::DECODER  & D::RAW & D::READ)
449         .withC2Mappers<C2Color::range_t>());
450     add(ConfigMapper(KEY_COLOR_TRANSFER,    C2_PARAMKEY_COLOR_ASPECTS,   "transfer")
451         .limitTo((D::VIDEO | D::IMAGE) & D::DECODER  & D::RAW & D::READ)
452         .withC2Mappers<C2Color::transfer_t>());
453     add(ConfigMapper("color-primaries",     C2_PARAMKEY_COLOR_ASPECTS,   "primaries")
454         .limitTo((D::VIDEO | D::IMAGE) & D::DECODER  & D::RAW & D::READ));
455     add(ConfigMapper("color-matrix",        C2_PARAMKEY_COLOR_ASPECTS,   "matrix")
456         .limitTo((D::VIDEO | D::IMAGE) & D::DECODER  & D::RAW & D::READ));
457 
458     // configure transfer request
459     add(ConfigMapper("color-transfer-request", C2_PARAMKEY_COLOR_ASPECTS, "transfer")
460         .limitTo((D::VIDEO | D::IMAGE) & D::DECODER  & D::RAW & D::CONFIG)
461         .withC2Mappers<C2Color::transfer_t>());
462 
463     // configure source aspects for encoders and read them back on the coded(!) port.
464     // This is to ensure muxing the desired aspects into the container.
465     add(ConfigMapper(KEY_COLOR_RANGE,       C2_PARAMKEY_COLOR_ASPECTS,   "range")
466         .limitTo((D::VIDEO | D::IMAGE) & D::ENCODER  & D::CODED)
467         .withC2Mappers<C2Color::range_t>());
468     add(ConfigMapper(KEY_COLOR_TRANSFER,    C2_PARAMKEY_COLOR_ASPECTS,   "transfer")
469         .limitTo((D::VIDEO | D::IMAGE) & D::ENCODER  & D::CODED)
470         .withC2Mappers<C2Color::transfer_t>());
471     add(ConfigMapper("color-primaries",     C2_PARAMKEY_COLOR_ASPECTS,   "primaries")
472         .limitTo((D::VIDEO | D::IMAGE) & D::ENCODER  & D::CODED));
473     add(ConfigMapper("color-matrix",        C2_PARAMKEY_COLOR_ASPECTS,   "matrix")
474         .limitTo((D::VIDEO | D::IMAGE) & D::ENCODER  & D::CODED));
475 
476     // read back coded aspects for encoders (on the raw port), but also configure
477     // desired aspects here.
478     add(ConfigMapper(KEY_COLOR_RANGE,       C2_PARAMKEY_VUI_COLOR_ASPECTS,   "range")
479         .limitTo((D::VIDEO | D::IMAGE) & D::ENCODER  & D::RAW)
480         .withC2Mappers<C2Color::range_t>());
481     add(ConfigMapper(KEY_COLOR_TRANSFER,    C2_PARAMKEY_VUI_COLOR_ASPECTS,   "transfer")
482         .limitTo((D::VIDEO | D::IMAGE) & D::ENCODER  & D::RAW)
483         .withC2Mappers<C2Color::transfer_t>());
484     add(ConfigMapper("color-primaries",     C2_PARAMKEY_VUI_COLOR_ASPECTS,   "primaries")
485         .limitTo((D::VIDEO | D::IMAGE) & D::ENCODER  & D::RAW));
486     add(ConfigMapper("color-matrix",        C2_PARAMKEY_VUI_COLOR_ASPECTS,   "matrix")
487         .limitTo((D::VIDEO | D::IMAGE) & D::ENCODER  & D::RAW));
488 
489     // Dataspace
490     add(ConfigMapper("android._dataspace", C2_PARAMKEY_DATA_SPACE, "value")
491         .limitTo((D::VIDEO | D::IMAGE) & D::RAW));
492 
493     // HDR
494     add(ConfigMapper("smpte2086.red.x", C2_PARAMKEY_HDR_STATIC_INFO, "mastering.red.x")
495         .limitTo((D::VIDEO | D::IMAGE) & D::RAW));
496     add(ConfigMapper("smpte2086.red.y", C2_PARAMKEY_HDR_STATIC_INFO, "mastering.red.y")
497         .limitTo((D::VIDEO | D::IMAGE) & D::RAW));
498     add(ConfigMapper("smpte2086.green.x", C2_PARAMKEY_HDR_STATIC_INFO, "mastering.green.x")
499         .limitTo((D::VIDEO | D::IMAGE) & D::RAW));
500     add(ConfigMapper("smpte2086.green.y", C2_PARAMKEY_HDR_STATIC_INFO, "mastering.green.y")
501         .limitTo((D::VIDEO | D::IMAGE) & D::RAW));
502     add(ConfigMapper("smpte2086.blue.x", C2_PARAMKEY_HDR_STATIC_INFO, "mastering.blue.x")
503         .limitTo((D::VIDEO | D::IMAGE) & D::RAW));
504     add(ConfigMapper("smpte2086.blue.y", C2_PARAMKEY_HDR_STATIC_INFO, "mastering.blue.y")
505         .limitTo((D::VIDEO | D::IMAGE) & D::RAW));
506     add(ConfigMapper("smpte2086.white.x", C2_PARAMKEY_HDR_STATIC_INFO, "mastering.white.x")
507         .limitTo((D::VIDEO | D::IMAGE) & D::RAW));
508     add(ConfigMapper("smpte2086.white.y", C2_PARAMKEY_HDR_STATIC_INFO, "mastering.white.y")
509         .limitTo((D::VIDEO | D::IMAGE) & D::RAW));
510     add(ConfigMapper("smpte2086.max-luminance", C2_PARAMKEY_HDR_STATIC_INFO, "mastering.max-luminance")
511         .limitTo((D::VIDEO | D::IMAGE) & D::RAW));
512     add(ConfigMapper("smpte2086.min-luminance", C2_PARAMKEY_HDR_STATIC_INFO, "mastering.min-luminance")
513         .limitTo((D::VIDEO | D::IMAGE) & D::RAW));
514     add(ConfigMapper("cta861.max-cll", C2_PARAMKEY_HDR_STATIC_INFO, "max-cll")
515         .limitTo((D::VIDEO | D::IMAGE) & D::RAW));
516     add(ConfigMapper("cta861.max-fall", C2_PARAMKEY_HDR_STATIC_INFO, "max-fall")
517         .limitTo((D::VIDEO | D::IMAGE) & D::RAW));
518 
519     add(ConfigMapper(C2_PARAMKEY_HDR_FORMAT, C2_PARAMKEY_HDR_FORMAT, "value")
520         .limitTo((D::VIDEO | D::IMAGE) & D::CODED & D::CONFIG));
521 
522     add(ConfigMapper(std::string(KEY_FEATURE_) + FEATURE_SecurePlayback,
523                      C2_PARAMKEY_SECURE_MODE, "value"));
524 
525     add(ConfigMapper(KEY_PREPEND_HEADER_TO_SYNC_FRAMES,
526                      C2_PARAMKEY_PREPEND_HEADER_MODE, "value")
527         .limitTo(D::ENCODER & D::VIDEO)
528         .withMappers([](C2Value v) -> C2Value {
529             int32_t value;
530             if (v.get(&value)) {
531                 return value ? C2Value(C2Config::PREPEND_HEADER_TO_ALL_SYNC)
532                              : C2Value(C2Config::PREPEND_HEADER_TO_NONE);
533             }
534             return C2Value();
535         }, [](C2Value v) -> C2Value {
536             C2Config::prepend_header_mode_t value;
537             using C2ValueType=typename _c2_reduce_enum_to_underlying_type<decltype(value)>::type;
538             if (v.get((C2ValueType *)&value)) {
539                 switch (value) {
540                     case C2Config::PREPEND_HEADER_TO_NONE:      return 0;
541                     case C2Config::PREPEND_HEADER_TO_ALL_SYNC:  return 1;
542                     case C2Config::PREPEND_HEADER_ON_CHANGE:    [[fallthrough]];
543                     default:                                    return C2Value();
544                 }
545             }
546             return C2Value();
547         }));
548     // remove when codecs switch to PARAMKEY
549     deprecated(ConfigMapper(KEY_PREPEND_HEADER_TO_SYNC_FRAMES,
550                             "coding.add-csd-to-sync-frames", "value")
551                .limitTo(D::ENCODER & D::VIDEO));
552     // convert to timestamp base
553     add(ConfigMapper(KEY_I_FRAME_INTERVAL, C2_PARAMKEY_SYNC_FRAME_INTERVAL, "value")
554         .limitTo(D::VIDEO & D::ENCODER & D::CONFIG)
555         .withMapper([](C2Value v) -> C2Value {
556             // convert from i32 to float
557             int32_t i32Value;
558             float fpValue;
559             if (v.get(&i32Value)) {
560                 return int64_t(1000000) * i32Value;
561             } else if (v.get(&fpValue)) {
562                 return int64_t(c2_min(1000000 * fpValue + 0.5, (double)INT64_MAX));
563             }
564             return C2Value();
565         }));
566     // remove when codecs switch to proper coding.gop (add support for calculating gop)
567     deprecated(ConfigMapper("i-frame-period", "coding.gop", "intra-period")
568                .limitTo(D::ENCODER & D::VIDEO));
569     add(ConfigMapper(KEY_INTRA_REFRESH_PERIOD, C2_PARAMKEY_INTRA_REFRESH, "period")
570         .limitTo(D::VIDEO & D::ENCODER)
571         .withMappers(makeFloat, [](C2Value v) -> C2Value {
572             // read back always as int
573             float value;
574             if (v.get(&value)) {
575                 return (int32_t)value;
576             }
577             return C2Value();
578         }));
579     deprecated(ConfigMapper(PARAMETER_KEY_REQUEST_SYNC_FRAME,
580                      "coding.request-sync", "value")
581         .limitTo(D::PARAM & D::ENCODER)
582         .withMapper([](C2Value) -> C2Value { return uint32_t(1); }));
583     add(ConfigMapper(PARAMETER_KEY_REQUEST_SYNC_FRAME,
584                      C2_PARAMKEY_REQUEST_SYNC_FRAME, "value")
585         .limitTo(D::PARAM & D::ENCODER)
586         .withMapper([](C2Value) -> C2Value { return uint32_t(1); }));
587 
588     add(ConfigMapper(KEY_OPERATING_RATE,   C2_PARAMKEY_OPERATING_RATE,     "value")
589         .limitTo(D::PARAM | D::CONFIG) // write-only
590         .withMapper(makeFloat));
591     // C2 priorities are inverted
592     add(ConfigMapper(KEY_PRIORITY,         C2_PARAMKEY_PRIORITY,           "value")
593         .withMappers(negate, negate));
594     // remove when codecs switch to PARAMKEY
595     deprecated(ConfigMapper(KEY_OPERATING_RATE,   "ctrl.operating-rate",     "value")
596                .withMapper(makeFloat));
597     deprecated(ConfigMapper(KEY_PRIORITY,         "ctrl.priority",           "value"));
598 
599     add(ConfigMapper(KEY_WIDTH,         C2_PARAMKEY_PICTURE_SIZE,       "width")
600         .limitTo(D::VIDEO | D::IMAGE));
601     add(ConfigMapper(KEY_HEIGHT,        C2_PARAMKEY_PICTURE_SIZE,       "height")
602         .limitTo(D::VIDEO | D::IMAGE));
603 
604     add(ConfigMapper("crop-left",       C2_PARAMKEY_CROP_RECT,       "left")
605         .limitTo(D::VIDEO | D::IMAGE));
606     add(ConfigMapper("crop-top",        C2_PARAMKEY_CROP_RECT,       "top")
607         .limitTo(D::VIDEO | D::IMAGE));
608     add(ConfigMapper("crop-width",      C2_PARAMKEY_CROP_RECT,       "width")
609         .limitTo(D::VIDEO | D::IMAGE));
610     add(ConfigMapper("crop-height",     C2_PARAMKEY_CROP_RECT,       "height")
611         .limitTo(D::VIDEO | D::IMAGE));
612 
613     add(ConfigMapper(KEY_MAX_WIDTH,     C2_PARAMKEY_MAX_PICTURE_SIZE,    "width")
614         .limitTo((D::VIDEO | D::IMAGE) & D::RAW));
615     add(ConfigMapper(KEY_MAX_HEIGHT,    C2_PARAMKEY_MAX_PICTURE_SIZE,    "height")
616         .limitTo((D::VIDEO | D::IMAGE) & D::RAW));
617 
618     add(ConfigMapper("csd-0",           C2_PARAMKEY_INIT_DATA,       "value")
619         .limitTo(D::OUTPUT & D::READ));
620 
621     deprecated(ConfigMapper(KEY_HDR10_PLUS_INFO, C2_PARAMKEY_INPUT_HDR10_PLUS_INFO, "value")
622         .limitTo(D::VIDEO & D::PARAM & D::INPUT));
623 
624     deprecated(ConfigMapper(KEY_HDR10_PLUS_INFO, C2_PARAMKEY_OUTPUT_HDR10_PLUS_INFO, "value")
625         .limitTo(D::VIDEO & D::OUTPUT));
626 
627     add(ConfigMapper(
628             std::string(C2_PARAMKEY_INPUT_HDR_DYNAMIC_INFO) + ".type",
629             C2_PARAMKEY_INPUT_HDR_DYNAMIC_INFO, "type")
630         .limitTo(D::VIDEO & D::PARAM & D::INPUT));
631 
632     add(ConfigMapper(
633             std::string(C2_PARAMKEY_INPUT_HDR_DYNAMIC_INFO) + ".data",
634             C2_PARAMKEY_INPUT_HDR_DYNAMIC_INFO, "data")
635         .limitTo(D::VIDEO & D::PARAM & D::INPUT));
636 
637     add(ConfigMapper(
638             std::string(C2_PARAMKEY_OUTPUT_HDR_DYNAMIC_INFO) + ".type",
639             C2_PARAMKEY_OUTPUT_HDR_DYNAMIC_INFO, "type")
640         .limitTo(D::VIDEO & D::OUTPUT));
641 
642     add(ConfigMapper(
643             std::string(C2_PARAMKEY_OUTPUT_HDR_DYNAMIC_INFO) + ".data",
644             C2_PARAMKEY_OUTPUT_HDR_DYNAMIC_INFO, "data")
645         .limitTo(D::VIDEO & D::OUTPUT));
646 
647     add(ConfigMapper(C2_PARAMKEY_TEMPORAL_LAYERING, C2_PARAMKEY_TEMPORAL_LAYERING, "")
648         .limitTo(D::ENCODER & D::VIDEO & D::OUTPUT));
649 
650     // Pixel Format (use local key for actual pixel format as we don't distinguish between
651     // SDK layouts for flexible format and we need the actual SDK color format in the media format)
652     add(ConfigMapper("android._color-format",  C2_PARAMKEY_PIXEL_FORMAT, "value")
653         .limitTo((D::VIDEO | D::IMAGE) & D::RAW)
654         .withMappers([](C2Value v) -> C2Value {
655             int32_t value;
656             if (v.get(&value)) {
657                 uint32_t result;
658                 if (C2Mapper::mapPixelFormatFrameworkToCodec(value, &result)) {
659                     return result;
660                 }
661             }
662             return C2Value();
663         }, [](C2Value v) -> C2Value {
664             uint32_t value;
665             if (v.get(&value)) {
666                 int32_t result;
667                 if (C2Mapper::mapPixelFormatCodecToFramework(value, &result)) {
668                     return result;
669                 }
670             }
671             return C2Value();
672         }));
673 
674     add(ConfigMapper(KEY_PIXEL_ASPECT_RATIO_WIDTH,  C2_PARAMKEY_PIXEL_ASPECT_RATIO, "width")
675         .limitTo((D::VIDEO | D::IMAGE) & D::RAW));
676     add(ConfigMapper(KEY_PIXEL_ASPECT_RATIO_HEIGHT, C2_PARAMKEY_PIXEL_ASPECT_RATIO, "height")
677         .limitTo((D::VIDEO | D::IMAGE) & D::RAW));
678 
679     add(ConfigMapper(KEY_CHANNEL_COUNT, C2_PARAMKEY_CHANNEL_COUNT,       "value")
680         .limitTo(D::AUDIO)); // read back to both formats
681     add(ConfigMapper(KEY_CHANNEL_COUNT, C2_PARAMKEY_CODED_CHANNEL_COUNT, "value")
682         .limitTo(D::AUDIO & D::CODED));
683 
684     add(ConfigMapper(KEY_SAMPLE_RATE,   C2_PARAMKEY_SAMPLE_RATE,        "value")
685         .limitTo(D::AUDIO)); // read back to both port formats
686     add(ConfigMapper(KEY_SAMPLE_RATE,   C2_PARAMKEY_CODED_SAMPLE_RATE,  "value")
687         .limitTo(D::AUDIO & D::CODED));
688 
689     auto pcmEncodingMapper = [](C2Value v) -> C2Value {
690         int32_t value;
691         C2Config::pcm_encoding_t to;
692         if (v.get(&value) && C2Mapper::map(value, &to)) {
693             return to;
694         }
695         return C2Value();
696     };
697     auto pcmEncodingReverse = [](C2Value v) -> C2Value {
698         C2Config::pcm_encoding_t value;
699         int32_t to;
700         using C2ValueType=typename _c2_reduce_enum_to_underlying_type<decltype(value)>::type;
701         if (v.get((C2ValueType*)&value) && C2Mapper::map(value, &to)) {
702             return to;
703         }
704         return C2Value();
705     };
706     add(ConfigMapper(KEY_PCM_ENCODING,              C2_PARAMKEY_PCM_ENCODING, "value")
707         .limitTo(D::AUDIO)
708         .withMappers(pcmEncodingMapper, pcmEncodingReverse));
709     add(ConfigMapper("android._codec-pcm-encoding", C2_PARAMKEY_PCM_ENCODING, "value")
710         .limitTo(D::AUDIO & D::READ)
711         .withMappers(pcmEncodingMapper, pcmEncodingReverse));
712 
713     add(ConfigMapper(KEY_IS_ADTS, C2_PARAMKEY_AAC_PACKAGING, "value")
714         .limitTo(D::AUDIO & D::CODED)
715         .withMappers([](C2Value v) -> C2Value {
716             int32_t value;
717             if (v.get(&value) && value) {
718                 return C2Config::AAC_PACKAGING_ADTS;
719             }
720             return C2Value();
721         }, [](C2Value v) -> C2Value {
722             uint32_t value;
723             if (v.get(&value) && value == C2Config::AAC_PACKAGING_ADTS) {
724                 return (int32_t)1;
725             }
726             return C2Value();
727         }));
728 
729     std::shared_ptr<C2Mapper::ProfileLevelMapper> mapper =
730         C2Mapper::GetProfileLevelMapper(mCodingMediaType);
731 
732     add(ConfigMapper(KEY_PROFILE, C2_PARAMKEY_PROFILE_LEVEL, "profile")
733         .limitTo(D::CODED)
734         .withMappers([mapper](C2Value v) -> C2Value {
735             C2Config::profile_t c2 = PROFILE_UNUSED;
736             int32_t sdk;
737             if (mapper && v.get(&sdk) && mapper->mapProfile(sdk, &c2)) {
738                 return c2;
739             }
740             return PROFILE_UNUSED;
741         }, [mapper](C2Value v) -> C2Value {
742             C2Config::profile_t c2;
743             int32_t sdk;
744             using C2ValueType=typename _c2_reduce_enum_to_underlying_type<decltype(c2)>::type;
745             if (mapper && v.get((C2ValueType*)&c2) && mapper->mapProfile(c2, &sdk)) {
746                 return sdk;
747             }
748             return C2Value();
749         }));
750 
751     add(ConfigMapper(KEY_LEVEL, C2_PARAMKEY_PROFILE_LEVEL, "level")
752         .limitTo(D::CODED)
753         .withMappers([mapper](C2Value v) -> C2Value {
754             C2Config::level_t c2 = LEVEL_UNUSED;
755             int32_t sdk;
756             if (mapper && v.get(&sdk) && mapper->mapLevel(sdk, &c2)) {
757                 return c2;
758             }
759             return LEVEL_UNUSED;
760         }, [mapper](C2Value v) -> C2Value {
761             C2Config::level_t c2;
762             int32_t sdk;
763             using C2ValueType=typename _c2_reduce_enum_to_underlying_type<decltype(c2)>::type;
764             if (mapper && v.get((C2ValueType*)&c2) && mapper->mapLevel(c2, &sdk)) {
765                 return sdk;
766             }
767             return C2Value();
768         }));
769 
770     add(ConfigMapper(KEY_AAC_PROFILE, C2_PARAMKEY_PROFILE_LEVEL, "profile")
771         .limitTo(D::AUDIO & D::ENCODER & (D::CONFIG | D::PARAM))
772         .withMapper([mapper](C2Value v) -> C2Value {
773             C2Config::profile_t c2 = PROFILE_UNUSED;
774             int32_t sdk;
775             if (mapper && v.get(&sdk) && mapper->mapProfile(sdk, &c2)) {
776                 return c2;
777             }
778             return PROFILE_UNUSED;
779         }));
780 
781     // convert to dBFS and add default
782     add(ConfigMapper(KEY_AAC_DRC_TARGET_REFERENCE_LEVEL, C2_PARAMKEY_DRC_TARGET_REFERENCE_LEVEL, "value")
783         .limitTo(D::AUDIO & D::DECODER & (D::CONFIG | D::PARAM | D::READ))
784         .withMappers([](C2Value v) -> C2Value {
785             int32_t value;
786             if (!v.get(&value) || value < -1) {
787                 value = property_get_int32(PROP_DRC_OVERRIDE_REF_LEVEL, DRC_DEFAULT_MOBILE_REF_LEVEL);
788             }
789             return float(-0.25 * c2_min(value, 127));
790         },[](C2Value v) -> C2Value {
791             float value;
792             if (v.get(&value)) {
793                 return (int32_t) (-4. * value);
794             }
795             return C2Value();
796         }));
797 
798     // convert to 0-1 (%) and add default
799     add(ConfigMapper(KEY_AAC_DRC_ATTENUATION_FACTOR, C2_PARAMKEY_DRC_ATTENUATION_FACTOR, "value")
800         .limitTo(D::AUDIO & D::DECODER & (D::CONFIG | D::PARAM | D::READ))
801         .withMappers([](C2Value v) -> C2Value {
802             int32_t value;
803             if (!v.get(&value) || value < 0) {
804                 value = property_get_int32(PROP_DRC_OVERRIDE_CUT, DRC_DEFAULT_MOBILE_DRC_CUT);
805             }
806             return float(c2_min(value, 127) / 127.);
807         },[](C2Value v) -> C2Value {
808             float value;
809             if (v.get(&value)) {
810               return (int32_t) (value * 127. + 0.5);
811             }
812             else {
813               return C2Value();
814             }
815         }));
816 
817     // convert to 0-1 (%) and add default
818     add(ConfigMapper(KEY_AAC_DRC_BOOST_FACTOR, C2_PARAMKEY_DRC_BOOST_FACTOR, "value")
819         .limitTo(D::AUDIO & D::DECODER & (D::CONFIG | D::PARAM | D::READ))
820         .withMappers([](C2Value v) -> C2Value {
821             int32_t value;
822             if (!v.get(&value) || value < 0) {
823                 value = property_get_int32(PROP_DRC_OVERRIDE_BOOST, DRC_DEFAULT_MOBILE_DRC_BOOST);
824             }
825             return float(c2_min(value, 127) / 127.);
826         },[](C2Value v) -> C2Value {
827             float value;
828             if (v.get(&value)) {
829               return (int32_t) (value * 127. + 0.5);
830             }
831             else {
832               return C2Value();
833             }
834         }));
835 
836     // convert to compression type and add default
837     add(ConfigMapper(KEY_AAC_DRC_HEAVY_COMPRESSION, C2_PARAMKEY_DRC_COMPRESSION_MODE, "value")
838         .limitTo(D::AUDIO & D::DECODER & (D::CONFIG | D::PARAM))
839         .withMapper([](C2Value v) -> C2Value {
840             int32_t value;
841             if (!v.get(&value) || value < 0) {
842                 value = property_get_int32(PROP_DRC_OVERRIDE_HEAVY, DRC_DEFAULT_MOBILE_DRC_HEAVY);
843             }
844             return value == 1 ? C2Config::DRC_COMPRESSION_HEAVY : C2Config::DRC_COMPRESSION_LIGHT;
845         }));
846 
847     // convert to dBFS and add default
848     add(ConfigMapper(KEY_AAC_ENCODED_TARGET_LEVEL, C2_PARAMKEY_DRC_ENCODED_TARGET_LEVEL, "value")
849         .limitTo(D::AUDIO & D::DECODER & (D::CONFIG | D::PARAM | D::READ))
850         .withMappers([](C2Value v) -> C2Value {
851             int32_t value;
852             if (!v.get(&value) || value < 0) {
853                 value = property_get_int32(PROP_DRC_OVERRIDE_ENC_LEVEL, DRC_DEFAULT_MOBILE_ENC_LEVEL);
854             }
855             return float(-0.25 * c2_min(value, 127));
856         },[](C2Value v) -> C2Value {
857             float value;
858             if (v.get(&value)) {
859               return (int32_t) (-4. * value);
860             }
861             else {
862               return C2Value();
863             }
864         }));
865 
866     // convert to effect type (these map to SDK values) and add default
867     add(ConfigMapper(KEY_AAC_DRC_EFFECT_TYPE, C2_PARAMKEY_DRC_EFFECT_TYPE, "value")
868         .limitTo(D::AUDIO & D::DECODER & (D::CONFIG | D::PARAM | D::READ))
869         .withMappers([](C2Value v) -> C2Value {
870             int32_t value;
871             if (!v.get(&value) || value < -1 || value > 8) {
872                 value = property_get_int32(PROP_DRC_OVERRIDE_EFFECT, DRC_DEFAULT_MOBILE_DRC_EFFECT);
873                 // ensure value is within range
874                 if (value < -1 || value > 8) {
875                     value = DRC_DEFAULT_MOBILE_DRC_EFFECT;
876                 }
877             }
878             return value;
879         },[](C2Value v) -> C2Value {
880             int32_t value;
881             if (v.get(&value)) {
882               return  value;
883             }
884             else {
885               return C2Value();
886             }
887         }));
888 
889     // convert to album mode and add default
890     add(ConfigMapper(KEY_AAC_DRC_ALBUM_MODE, C2_PARAMKEY_DRC_ALBUM_MODE, "value")
891         .limitTo(D::AUDIO & D::DECODER & (D::CONFIG | D::PARAM | D::READ))
892         .withMappers([](C2Value v) -> C2Value {
893             int32_t value;
894             if (!v.get(&value) || value < 0 || value > 1) {
895                 value = DRC_DEFAULT_MOBILE_DRC_ALBUM;
896                 // ensure value is within range
897                 if (value < 0 || value > 1) {
898                     value = DRC_DEFAULT_MOBILE_DRC_ALBUM;
899                 }
900             }
901             return value;
902         },[](C2Value v) -> C2Value {
903             int32_t value;
904             if (v.get(&value)) {
905               return value;
906             }
907             else {
908               return C2Value();
909             }
910         }));
911 
912     add(ConfigMapper(KEY_AAC_DRC_OUTPUT_LOUDNESS, C2_PARAMKEY_DRC_OUTPUT_LOUDNESS, "value")
913         .limitTo(D::OUTPUT & D::DECODER & D::READ)
914         .withMappers([](C2Value v) -> C2Value {
915             int32_t value;
916             if (!v.get(&value) || value < -1) {
917                 value = DRC_DEFAULT_MOBILE_OUTPUT_LOUDNESS;
918             }
919             return float(-0.25 * c2_min(value, 127));
920         },[](C2Value v) -> C2Value {
921             float value;
922             if (v.get(&value)) {
923                 return (int32_t) (-4. * value);
924             }
925             return C2Value();
926         }));
927 
928     add(ConfigMapper(KEY_AAC_MAX_OUTPUT_CHANNEL_COUNT, C2_PARAMKEY_MAX_CHANNEL_COUNT, "value")
929         .limitTo(D::AUDIO & (D::CONFIG | D::PARAM | D::READ)));
930 
931     add(ConfigMapper(KEY_MAX_OUTPUT_CHANNEL_COUNT, C2_PARAMKEY_MAX_CHANNEL_COUNT, "value")
932         .limitTo(D::AUDIO & (D::CONFIG | D::PARAM | D::READ)));
933 
934     add(ConfigMapper(KEY_CHANNEL_MASK, C2_PARAMKEY_CHANNEL_MASK, "value")
935         .limitTo(D::AUDIO & D::DECODER & D::READ));
936 
937     add(ConfigMapper(KEY_AAC_SBR_MODE, C2_PARAMKEY_AAC_SBR_MODE, "value")
938         .limitTo(D::AUDIO & D::ENCODER & (D::CONFIG | D::PARAM | D::READ))
939         .withMapper([](C2Value v) -> C2Value {
940             int32_t value;
941             if (!v.get(&value) || value < 0) {
942                 return C2Config::AAC_SBR_AUTO;
943             }
944             switch (value) {
945                 case 0: return C2Config::AAC_SBR_OFF;
946                 case 1: return C2Config::AAC_SBR_SINGLE_RATE;
947                 case 2: return C2Config::AAC_SBR_DUAL_RATE;
948                 default: return C2Config::AAC_SBR_AUTO + 1; // invalid value
949             }
950         }));
951 
952     add(ConfigMapper("android._encoding-quality-level", C2_PARAMKEY_ENCODING_QUALITY_LEVEL, "value")
953         .limitTo(D::ENCODER & (D::CONFIG | D::PARAM)));
954     add(ConfigMapper(KEY_QUALITY, C2_PARAMKEY_QUALITY, "value")
955         .limitTo(D::ENCODER & (D::CONFIG | D::PARAM)));
956     add(ConfigMapper(KEY_FLAC_COMPRESSION_LEVEL, C2_PARAMKEY_COMPLEXITY, "value")
957         .limitTo(D::AUDIO & D::ENCODER));
958     add(ConfigMapper("complexity", C2_PARAMKEY_COMPLEXITY, "value")
959         .limitTo(D::ENCODER & (D::CONFIG | D::PARAM)));
960 
961     add(ConfigMapper(KEY_GRID_COLUMNS, C2_PARAMKEY_TILE_LAYOUT, "columns")
962         .limitTo(D::IMAGE));
963     add(ConfigMapper(KEY_GRID_ROWS, C2_PARAMKEY_TILE_LAYOUT, "rows")
964         .limitTo(D::IMAGE));
965     add(ConfigMapper(KEY_TILE_WIDTH, C2_PARAMKEY_TILE_LAYOUT, "tile.width")
966         .limitTo(D::IMAGE));
967     add(ConfigMapper(KEY_TILE_HEIGHT, C2_PARAMKEY_TILE_LAYOUT, "tile.height")
968         .limitTo(D::IMAGE));
969 
970     add(ConfigMapper(KEY_LATENCY, C2_PARAMKEY_PIPELINE_DELAY_REQUEST, "value")
971         .limitTo(D::VIDEO & D::ENCODER));
972 
973     add(ConfigMapper(C2_PARAMKEY_INPUT_TIME_STRETCH, C2_PARAMKEY_INPUT_TIME_STRETCH, "value"));
974 
975     add(ConfigMapper(KEY_LOW_LATENCY, C2_PARAMKEY_LOW_LATENCY_MODE, "value")
976         .limitTo(D::DECODER & (D::CONFIG | D::PARAM))
977         .withMapper([](C2Value v) -> C2Value {
978             int32_t value = 0;
979             (void)v.get(&value);
980             return value == 0 ? C2_FALSE : C2_TRUE;
981         }));
982 
983     add(ConfigMapper("android._trigger-tunnel-peek", C2_PARAMKEY_TUNNEL_START_RENDER, "value")
984         .limitTo(D::PARAM & D::VIDEO & D::DECODER)
985         .withMapper([](C2Value v) -> C2Value {
986             int32_t value = 0;
987             (void)v.get(&value);
988             return value == 0 ? C2_FALSE : C2_TRUE;
989         }));
990 
991     add(ConfigMapper("android._tunnel-peek-set-legacy", C2_PARAMKEY_TUNNEL_PEEK_MODE, "value")
992         .limitTo(D::PARAM & D::VIDEO & D::DECODER)
993         .withMapper([](C2Value v) -> C2Value {
994           int32_t value = 0;
995           (void)v.get(&value);
996           return value == 0
997               ? C2Value(C2PlatformConfig::SPECIFIED_PEEK)
998               : C2Value(C2PlatformConfig::UNSPECIFIED_PEEK);
999         }));
1000 
1001     add(ConfigMapper(KEY_VIDEO_QP_AVERAGE, C2_PARAMKEY_AVERAGE_QP, "value")
1002         .limitTo(D::ENCODER & D::VIDEO & D::READ));
1003 
1004     add(ConfigMapper(KEY_PICTURE_TYPE, C2_PARAMKEY_PICTURE_TYPE, "value")
1005         .limitTo(D::ENCODER & D::VIDEO & D::READ)
1006         .withMappers([](C2Value v) -> C2Value {
1007             int32_t sdk;
1008             C2Config::picture_type_t c2;
1009             if (v.get(&sdk) && C2Mapper::map(sdk, &c2)) {
1010                 return C2Value(c2);
1011             }
1012             return C2Value();
1013         }, [](C2Value v) -> C2Value {
1014             C2Config::picture_type_t c2;
1015             int32_t sdk = PICTURE_TYPE_UNKNOWN;
1016             using C2ValueType=typename _c2_reduce_enum_to_underlying_type<decltype(c2)>::type;
1017             if (v.get((C2ValueType*)&c2) && C2Mapper::map(c2, &sdk)) {
1018                 return sdk;
1019             }
1020             return C2Value();
1021         }));
1022 
1023     /* still to do
1024        not yet used by MediaCodec, but defined as MediaFormat
1025     KEY_AUDIO_SESSION_ID // we use "audio-hw-sync"
1026     KEY_OUTPUT_REORDER_DEPTH
1027     */
1028 }
1029 
initialize(const std::shared_ptr<C2ParamReflector> & reflector,const std::shared_ptr<Codec2Client::Configurable> & configurable)1030 status_t CCodecConfig::initialize(
1031         const std::shared_ptr<C2ParamReflector> &reflector,
1032         const std::shared_ptr<Codec2Client::Configurable> &configurable) {
1033     C2ComponentDomainSetting domain(C2Component::DOMAIN_OTHER);
1034     C2ComponentKindSetting kind(C2Component::KIND_OTHER);
1035 
1036     std::vector<std::unique_ptr<C2Param>> queried;
1037     c2_status_t c2err = configurable->query({ &domain, &kind }, {}, C2_DONT_BLOCK, &queried);
1038     if (c2err != C2_OK) {
1039         ALOGD("Query domain & kind failed => %s", asString(c2err));
1040         // TEMP: determine kind from component name
1041         if (kind.value == C2Component::KIND_OTHER) {
1042             if (configurable->getName().find("encoder") != std::string::npos) {
1043                 kind.value = C2Component::KIND_ENCODER;
1044             } else if (configurable->getName().find("decoder") != std::string::npos) {
1045                 kind.value = C2Component::KIND_DECODER;
1046             }
1047         }
1048 
1049         // TEMP: determine domain from media type (port (preferred) or stream #0)
1050         if (domain.value == C2Component::DOMAIN_OTHER) {
1051             AString mediaType = QueryMediaType(true /* input */, configurable);
1052             if (mediaType.startsWith("audio/")) {
1053                 domain.value = C2Component::DOMAIN_AUDIO;
1054             } else if (mediaType.startsWith("video/")) {
1055                 domain.value = C2Component::DOMAIN_VIDEO;
1056             } else if (mediaType.startsWith("image/")) {
1057                 domain.value = C2Component::DOMAIN_IMAGE;
1058             }
1059         }
1060     }
1061 
1062     mDomain = (domain.value == C2Component::DOMAIN_VIDEO ? Domain::IS_VIDEO :
1063                domain.value == C2Component::DOMAIN_IMAGE ? Domain::IS_IMAGE :
1064                domain.value == C2Component::DOMAIN_AUDIO ? Domain::IS_AUDIO : Domain::OTHER_DOMAIN)
1065             | (kind.value == C2Component::KIND_DECODER ? Domain::IS_DECODER :
1066                kind.value == C2Component::KIND_ENCODER ? Domain::IS_ENCODER : Domain::OTHER_KIND);
1067 
1068     mInputDomain = Domain(((mDomain & IS_DECODER) ? IS_CODED : IS_RAW) | IS_INPUT);
1069     mOutputDomain = Domain(((mDomain & IS_ENCODER) ? IS_CODED : IS_RAW) | IS_OUTPUT);
1070 
1071     ALOGV("domain is %#x (%u %u)", mDomain, domain.value, kind.value);
1072 
1073     std::vector<C2Param::Index> paramIndices;
1074     switch (kind.value) {
1075     case C2Component::KIND_DECODER:
1076         mCodingMediaType = QueryMediaType(true /* input */, configurable).c_str();
1077         break;
1078     case C2Component::KIND_ENCODER:
1079         mCodingMediaType = QueryMediaType(false /* input */, configurable).c_str();
1080         break;
1081     default:
1082         mCodingMediaType = "";
1083     }
1084 
1085     c2err = configurable->querySupportedParams(&mParamDescs);
1086     if (c2err != C2_OK) {
1087         ALOGD("Query supported params failed after returning %zu values => %s",
1088                 mParamDescs.size(), asString(c2err));
1089         return UNKNOWN_ERROR;
1090     }
1091     for (const std::shared_ptr<C2ParamDescriptor> &desc : mParamDescs) {
1092         mSupportedIndices.emplace(desc->index());
1093     }
1094 
1095     mReflector = reflector;
1096     if (mReflector == nullptr) {
1097         ALOGE("Null param reflector");
1098         return UNKNOWN_ERROR;
1099     }
1100 
1101     // enumerate all fields
1102     mParamUpdater = std::make_shared<ReflectedParamUpdater>();
1103     mParamUpdater->clear();
1104     mParamUpdater->supportWholeParam(
1105             C2_PARAMKEY_TEMPORAL_LAYERING, C2StreamTemporalLayeringTuning::CORE_INDEX);
1106     mParamUpdater->addParamDesc(mReflector, mParamDescs);
1107 
1108     // TEMP: add some standard fields even if not reflected
1109     if (kind.value == C2Component::KIND_ENCODER) {
1110         mParamUpdater->addStandardParam<C2StreamInitDataInfo::output>(C2_PARAMKEY_INIT_DATA);
1111     }
1112     if (domain.value == C2Component::DOMAIN_IMAGE || domain.value == C2Component::DOMAIN_VIDEO) {
1113         if (kind.value != C2Component::KIND_ENCODER) {
1114             addLocalParam<C2StreamPictureSizeInfo::output>(C2_PARAMKEY_PICTURE_SIZE);
1115             addLocalParam<C2StreamCropRectInfo::output>(C2_PARAMKEY_CROP_RECT);
1116             addLocalParam(
1117                     new C2StreamPixelAspectRatioInfo::output(0u, 1u, 1u),
1118                     C2_PARAMKEY_PIXEL_ASPECT_RATIO);
1119             addLocalParam(new C2StreamRotationInfo::output(0u, 0), C2_PARAMKEY_ROTATION);
1120             addLocalParam(
1121                     new C2StreamColorAspectsTuning::output(0u),
1122                     C2_PARAMKEY_DEFAULT_COLOR_ASPECTS);
1123             addLocalParam<C2StreamDataSpaceInfo::output>(C2_PARAMKEY_DATA_SPACE);
1124             addLocalParam<C2StreamHdrStaticInfo::output>(C2_PARAMKEY_HDR_STATIC_INFO);
1125             addLocalParam(
1126                     new C2StreamSurfaceScalingInfo::output(0u, VIDEO_SCALING_MODE_SCALE_TO_FIT),
1127                     C2_PARAMKEY_SURFACE_SCALING_MODE);
1128         } else {
1129             addLocalParam(new C2StreamColorAspectsInfo::input(0u), C2_PARAMKEY_COLOR_ASPECTS);
1130 
1131             if (domain.value == C2Component::DOMAIN_VIDEO) {
1132                 addLocalParam(new C2AndroidStreamAverageBlockQuantizationInfo::output(0u, 0),
1133                               C2_PARAMKEY_AVERAGE_QP);
1134                 addLocalParam(new C2StreamPictureTypeInfo::output(0u, 0),
1135                               C2_PARAMKEY_PICTURE_TYPE);
1136             }
1137         }
1138     }
1139 
1140     initializeStandardParams();
1141 
1142     // subscribe to all supported standard (exposed) params
1143     // TODO: limit this to params that are actually in the domain
1144     std::vector<std::string> formatKeys = mStandardParams->getPathsForDomain(Domain(1 << 30));
1145     std::vector<C2Param::Index> indices;
1146     mParamUpdater->getParamIndicesForKeys(formatKeys, &indices);
1147     mSubscribedIndices.insert(indices.begin(), indices.end());
1148 
1149     // also subscribe to some non-SDK standard parameters
1150     // for number of input/output buffers
1151     mSubscribedIndices.emplace(C2PortSuggestedBufferCountTuning::input::PARAM_TYPE);
1152     mSubscribedIndices.emplace(C2PortSuggestedBufferCountTuning::output::PARAM_TYPE);
1153     mSubscribedIndices.emplace(C2ActualPipelineDelayTuning::PARAM_TYPE);
1154     mSubscribedIndices.emplace(C2PortActualDelayTuning::input::PARAM_TYPE);
1155     mSubscribedIndices.emplace(C2PortActualDelayTuning::output::PARAM_TYPE);
1156     // for output buffer array allocation
1157     mSubscribedIndices.emplace(C2StreamMaxBufferSizeInfo::output::PARAM_TYPE);
1158     // init data (CSD)
1159     mSubscribedIndices.emplace(C2StreamInitDataInfo::output::PARAM_TYPE);
1160 
1161     for (const std::shared_ptr<C2ParamDescriptor> &desc : mParamDescs) {
1162         if (desc->index().isVendor()) {
1163             std::vector<std::string> keys;
1164             mParamUpdater->getKeysForParamIndex(desc->index(), &keys);
1165             for (const std::string &key : keys) {
1166                 mVendorParams.insert_or_assign(key, desc);
1167             }
1168         }
1169     }
1170 
1171     // Parameters that are not subscribed initially, but can be subscribed
1172     // upon explicit request.
1173     static const std::initializer_list<C2Param::Index> kOptionalParams = {
1174         C2AndroidStreamAverageBlockQuantizationInfo::output::PARAM_TYPE,
1175         C2StreamPictureTypeInfo::output::PARAM_TYPE,
1176     };
1177     for (const C2Param::Index &index : kOptionalParams) {
1178         mSubscribedIndices.erase(index);
1179     }
1180     subscribeToConfigUpdate(configurable, {}, C2_MAY_BLOCK);
1181 
1182     return OK;
1183 }
1184 
subscribeToConfigUpdate(const std::shared_ptr<Codec2Client::Configurable> & configurable,const std::vector<C2Param::Index> & indices,c2_blocking_t blocking)1185 status_t CCodecConfig::subscribeToConfigUpdate(
1186         const std::shared_ptr<Codec2Client::Configurable> &configurable,
1187         const std::vector<C2Param::Index> &indices,
1188         c2_blocking_t blocking) {
1189     static const int32_t kProductFirstApiLevel =
1190         base::GetIntProperty<int32_t>("ro.product.first_api_level", 0);
1191     static const int32_t kBoardApiLevel =
1192         base::GetIntProperty<int32_t>("ro.board.first_api_level", 0);
1193     static const int32_t kFirstApiLevel =
1194         (kBoardApiLevel != 0) ? kBoardApiLevel : kProductFirstApiLevel;
1195     mSubscribedIndices.insert(indices.begin(), indices.end());
1196     if (mSubscribedIndices.size() != mSubscribedIndicesSize
1197             && kFirstApiLevel >= __ANDROID_API_T__) {
1198         std::vector<uint32_t> indicesVector;
1199         for (C2Param::Index ix : mSubscribedIndices) {
1200             indicesVector.push_back(ix);
1201         }
1202         std::unique_ptr<C2SubscribedParamIndicesTuning> subscribeTuning =
1203             C2SubscribedParamIndicesTuning::AllocUnique(indicesVector);
1204         std::vector<std::unique_ptr<C2SettingResult>> results;
1205         c2_status_t c2Err = configurable->config({ subscribeTuning.get() }, blocking, &results);
1206         if (c2Err != C2_OK && c2Err != C2_BAD_INDEX) {
1207             ALOGD("Failed to subscribe to parameters => %s", asString(c2Err));
1208             // TODO: error
1209         }
1210         ALOGV("Subscribed to %zu params", mSubscribedIndices.size());
1211         mSubscribedIndicesSize = mSubscribedIndices.size();
1212     }
1213 #if defined(LOG_NDEBUG) && !LOG_NDEBUG
1214     ALOGV("subscribed to %zu params:", mSubscribedIndices.size());
1215     std::stringstream ss;
1216     for (const C2Param::Index &index : mSubscribedIndices) {
1217         ss << index << " ";
1218         if (ss.str().length() > 70) {
1219             ALOGV("%s", ss.str().c_str());
1220             std::stringstream().swap(ss);
1221         }
1222     }
1223     if (!ss.str().empty()) {
1224         ALOGV("%s", ss.str().c_str());
1225     }
1226 #endif
1227     return OK;
1228 }
1229 
queryConfiguration(const std::shared_ptr<Codec2Client::Configurable> & configurable)1230 status_t CCodecConfig::queryConfiguration(
1231         const std::shared_ptr<Codec2Client::Configurable> &configurable) {
1232     // query all subscribed parameters
1233     std::vector<C2Param::Index> indices(mSubscribedIndices.begin(), mSubscribedIndices.end());
1234     std::vector<std::unique_ptr<C2Param>> queried;
1235     c2_status_t c2Err = configurable->query({}, indices, C2_MAY_BLOCK, &queried);
1236     if (c2Err != OK) {
1237         ALOGI("query failed after returning %zu values (%s)", queried.size(), asString(c2Err));
1238         // TODO: error
1239     }
1240 
1241     updateConfiguration(queried, ALL);
1242     return OK;
1243 }
1244 
updateConfiguration(std::vector<std::unique_ptr<C2Param>> & configUpdate,Domain domain)1245 bool CCodecConfig::updateConfiguration(
1246         std::vector<std::unique_ptr<C2Param>> &configUpdate, Domain domain) {
1247     ALOGV("updating configuration with %zu params", configUpdate.size());
1248     bool changed = false;
1249     for (std::unique_ptr<C2Param> &p : configUpdate) {
1250         if (p && *p) {
1251             // Allow unsubscribed vendor parameters to go through --- it may be
1252             // later handled by the format shaper.
1253             if (!p->isVendor() && mSubscribedIndices.count(p->index()) == 0) {
1254                 ALOGV("updateConfiguration: skipped unsubscribed param %08x", p->index());
1255                 continue;
1256             }
1257             auto insertion = mCurrentConfig.emplace(p->index(), nullptr);
1258             if (insertion.second || *insertion.first->second != *p) {
1259                 if (mSupportedIndices.count(p->index()) || mLocalParams.count(p->index())) {
1260                     // only track changes in supported (reflected or local) indices
1261                     changed = true;
1262                 } else {
1263                     ALOGV("an unlisted config was %s: %#x",
1264                             insertion.second ? "added" : "updated", p->index());
1265                 }
1266             }
1267             insertion.first->second = std::move(p);
1268         }
1269     }
1270     if (mInputSurface
1271             && (domain & mOutputDomain)
1272             && mInputSurfaceDataspace != mInputSurface->getDataspace()) {
1273         changed = true;
1274         mInputSurfaceDataspace = mInputSurface->getDataspace();
1275     }
1276 
1277     ALOGV("updated configuration has %zu params (%s)", mCurrentConfig.size(),
1278             changed ? "CHANGED" : "no change");
1279     if (changed) {
1280         return updateFormats(domain);
1281     }
1282     return false;
1283 }
1284 
updateFormats(Domain domain)1285 bool CCodecConfig::updateFormats(Domain domain) {
1286     // get addresses of params in the current config
1287     std::vector<C2Param*> paramPointers;
1288     for (const auto &it : mCurrentConfig) {
1289         paramPointers.push_back(it.second.get());
1290     }
1291 
1292     ReflectedParamUpdater::Dict reflected = mParamUpdater->getParams(paramPointers);
1293     std::string config = reflected.debugString();
1294     std::set<std::string> configLines;
1295     std::string diff;
1296     for (size_t start = 0; start != std::string::npos; ) {
1297         size_t end = config.find('\n', start);
1298         size_t count = (end == std::string::npos)
1299                 ? std::string::npos
1300                 : end - start + 1;
1301         std::string line = config.substr(start, count);
1302         configLines.insert(line);
1303         if (mLastConfig.count(line) == 0) {
1304             diff.append(line);
1305         }
1306         start = (end == std::string::npos) ? std::string::npos : end + 1;
1307     }
1308     if (!diff.empty()) {
1309         ALOGD("c2 config diff is %s", diff.c_str());
1310     }
1311     mLastConfig.swap(configLines);
1312 
1313     bool changed = false;
1314     if (domain & mInputDomain) {
1315         sp<AMessage> oldFormat = mInputFormat;
1316         mInputFormat = mInputFormat->dup(); // trigger format changed
1317         mInputFormat->extend(getFormatForDomain(reflected, mInputDomain));
1318         if (mInputFormat->countEntries() != oldFormat->countEntries()
1319                 || mInputFormat->changesFrom(oldFormat)->countEntries() > 0) {
1320             changed = true;
1321         } else {
1322             mInputFormat = oldFormat; // no change
1323         }
1324     }
1325     if (domain & mOutputDomain) {
1326         sp<AMessage> oldFormat = mOutputFormat;
1327         mOutputFormat = mOutputFormat->dup(); // trigger output format changed
1328         mOutputFormat->extend(getFormatForDomain(reflected, mOutputDomain));
1329         if (mOutputFormat->countEntries() != oldFormat->countEntries()
1330                 || mOutputFormat->changesFrom(oldFormat)->countEntries() > 0) {
1331             changed = true;
1332         } else {
1333             mOutputFormat = oldFormat; // no change
1334         }
1335     }
1336     ALOGV_IF(changed, "format(s) changed");
1337     return changed;
1338 }
1339 
getFormatForDomain(const ReflectedParamUpdater::Dict & reflected,Domain portDomain) const1340 sp<AMessage> CCodecConfig::getFormatForDomain(
1341         const ReflectedParamUpdater::Dict &reflected,
1342         Domain portDomain) const {
1343     sp<AMessage> msg = new AMessage;
1344     for (const auto &[key, mappers] : mStandardParams->getKeys()) {
1345         for (const ConfigMapper &cm : mappers) {
1346             if ((cm.domain() & portDomain) == 0 // input-output-coded-raw
1347                 || (cm.domain() & mDomain) != mDomain // component domain + kind (these must match)
1348                 || (cm.domain() & IS_READ) == 0) {
1349                 continue;
1350             }
1351             auto it = reflected.find(cm.path());
1352             if (it == reflected.end()) {
1353                 continue;
1354             }
1355             C2Value c2Value;
1356             sp<ABuffer> bufValue;
1357             AString strValue;
1358             AMessage::ItemData item;
1359             if (it->second.find(&c2Value)) {
1360                 item = cm.mapToMessage(c2Value);
1361             } else if (it->second.find(&bufValue)) {
1362                 item.set(bufValue);
1363             } else if (it->second.find(&strValue)) {
1364                 item.set(strValue);
1365             } else {
1366                 ALOGD("unexpected untyped query value for key: %s", cm.path().c_str());
1367                 continue;
1368             }
1369             msg->setItem(key.c_str(), item);
1370         }
1371     }
1372 
1373     bool input = (portDomain & Domain::IS_INPUT);
1374     std::vector<std::string> vendorKeys;
1375     for (const auto &[key, value] : reflected) {
1376         auto it = mVendorParams.find(key);
1377         if (it == mVendorParams.end()) {
1378             continue;
1379         }
1380         C2Param::Index index = it->second->index();
1381         if (mSubscribedIndices.count(index) == 0) {
1382             continue;
1383         }
1384         // For vendor parameters, we only care about direction
1385         if ((input && !index.forInput())
1386                 || (!input && !index.forOutput())) {
1387             continue;
1388         }
1389         C2Value c2Value;
1390         sp<ABuffer> bufValue;
1391         AString strValue;
1392         AMessage::ItemData item;
1393         if (value.find(&c2Value)) {
1394             C2ValueToMessageItem(c2Value, item);
1395         } else if (value.find(&bufValue)) {
1396             item.set(bufValue);
1397         } else if (value.find(&strValue)) {
1398             item.set(strValue);
1399         } else {
1400             ALOGD("unexpected untyped query value for key: %s", key.c_str());
1401             continue;
1402         }
1403         msg->setItem(key.c_str(), item);
1404     }
1405 
1406     { // convert from Codec 2.0 rect to MediaFormat rect and add crop rect if not present
1407         int32_t left, top, width, height;
1408         if (msg->findInt32("crop-left", &left) && msg->findInt32("crop-width", &width)
1409                 && msg->findInt32("crop-top", &top) && msg->findInt32("crop-height", &height)
1410                 && left >= 0 && width >=0 && width <= INT32_MAX - left
1411                 && top >= 0 && height >=0 && height <= INT32_MAX - top) {
1412             msg->removeEntryAt(msg->findEntryByName("crop-left"));
1413             msg->removeEntryAt(msg->findEntryByName("crop-top"));
1414             msg->removeEntryAt(msg->findEntryByName("crop-width"));
1415             msg->removeEntryAt(msg->findEntryByName("crop-height"));
1416             msg->setRect("crop", left, top, left + width - 1, top + height - 1);
1417         } else if (msg->findInt32("width", &width) && msg->findInt32("height", &height)) {
1418             msg->setRect("crop", 0, 0, width - 1, height - 1);
1419         }
1420     }
1421 
1422     { // convert temporal layering to schema
1423         sp<ABuffer> tmp;
1424         if (msg->findBuffer(C2_PARAMKEY_TEMPORAL_LAYERING, &tmp) && tmp != nullptr) {
1425             C2StreamTemporalLayeringTuning *layering =
1426                 C2StreamTemporalLayeringTuning::From(C2Param::From(tmp->data(), tmp->size()));
1427             if (layering && layering->m.layerCount > 0
1428                     && layering->m.bLayerCount < layering->m.layerCount) {
1429                 // check if this is webrtc compatible
1430                 AString mime;
1431                 if (msg->findString(KEY_MIME, &mime) &&
1432                         mime.equalsIgnoreCase(MIMETYPE_VIDEO_VP8) &&
1433                         layering->m.bLayerCount == 0 &&
1434                         (layering->m.layerCount == 1
1435                                 || (layering->m.layerCount == 2
1436                                         && layering->flexCount() >= 1
1437                                         && layering->m.bitrateRatios[0] == .6f)
1438                                 || (layering->m.layerCount == 3
1439                                         && layering->flexCount() >= 2
1440                                         && layering->m.bitrateRatios[0] == .4f
1441                                         && layering->m.bitrateRatios[1] == .6f)
1442                                 || (layering->m.layerCount == 4
1443                                         && layering->flexCount() >= 3
1444                                         && layering->m.bitrateRatios[0] == .25f
1445                                         && layering->m.bitrateRatios[1] == .4f
1446                                         && layering->m.bitrateRatios[2] == .6f))) {
1447                     msg->setString(KEY_TEMPORAL_LAYERING, AStringPrintf(
1448                             "webrtc.vp8.%u-layer", layering->m.layerCount));
1449                 } else if (layering->m.bLayerCount) {
1450                     msg->setString(KEY_TEMPORAL_LAYERING, AStringPrintf(
1451                             "android.generic.%u+%u",
1452                             layering->m.layerCount - layering->m.bLayerCount,
1453                             layering->m.bLayerCount));
1454                 } else if (layering->m.bLayerCount) {
1455                     msg->setString(KEY_TEMPORAL_LAYERING, AStringPrintf(
1456                             "android.generic.%u", layering->m.layerCount));
1457                 }
1458             }
1459             msg->removeEntryAt(msg->findEntryByName(C2_PARAMKEY_TEMPORAL_LAYERING));
1460         }
1461     }
1462 
1463     // Remove KEY_AAC_SBR_MODE from SDK message if it is outside supported range
1464     // as SDK doesn't have a way to signal default sbr mode based on profile and
1465     // requires that the key isn't present in format to signal that
1466     int sbrMode;
1467     if (msg->findInt32(KEY_AAC_SBR_MODE, &sbrMode) && (sbrMode < 0 || sbrMode > 2)) {
1468         msg->removeEntryAt(msg->findEntryByName(KEY_AAC_SBR_MODE));
1469     }
1470 
1471     { // convert color info
1472         // move default color to color aspect if not read from the component
1473         int32_t tmp;
1474         int32_t range;
1475         if (msg->findInt32("default-color-range", &range)) {
1476             if (!msg->findInt32(KEY_COLOR_RANGE, &tmp)) {
1477                 msg->setInt32(KEY_COLOR_RANGE, range);
1478             }
1479             msg->removeEntryAt(msg->findEntryByName("default-color-range"));
1480         }
1481         int32_t transfer;
1482         if (msg->findInt32("default-color-transfer", &transfer)) {
1483             if (!msg->findInt32(KEY_COLOR_TRANSFER, &tmp)) {
1484                 msg->setInt32(KEY_COLOR_TRANSFER, transfer);
1485             }
1486             msg->removeEntryAt(msg->findEntryByName("default-color-transfer"));
1487         }
1488         C2Color::primaries_t primaries;
1489         if (msg->findInt32("default-color-primaries", (int32_t*)&primaries)) {
1490             if (!msg->findInt32("color-primaries", &tmp)) {
1491                 msg->setInt32("color-primaries", primaries);
1492             }
1493             msg->removeEntryAt(msg->findEntryByName("default-color-primaries"));
1494         }
1495         C2Color::matrix_t matrix;
1496         if (msg->findInt32("default-color-matrix", (int32_t*)&matrix)) {
1497             if (!msg->findInt32("color-matrix", &tmp)) {
1498                 msg->setInt32("color-matrix", matrix);
1499             }
1500             msg->removeEntryAt(msg->findEntryByName("default-color-matrix"));
1501         }
1502 
1503         if (msg->findInt32("color-primaries", (int32_t*)&primaries)
1504                 && msg->findInt32("color-matrix", (int32_t*)&matrix)) {
1505             int32_t standard;
1506 
1507             if (C2Mapper::map(primaries, matrix, &standard)) {
1508                 msg->setInt32(KEY_COLOR_STANDARD, standard);
1509             }
1510 
1511             msg->removeEntryAt(msg->findEntryByName("color-primaries"));
1512             msg->removeEntryAt(msg->findEntryByName("color-matrix"));
1513         }
1514 
1515         // calculate dataspace for raw graphic buffers if not specified by component, or if
1516         // using surface with unspecified aspects (as those must be defaulted which may change
1517         // the dataspace)
1518         if ((portDomain & IS_RAW) && (mDomain & (IS_IMAGE | IS_VIDEO))) {
1519             android_dataspace dataspace;
1520             ColorAspects aspects = {
1521                 ColorAspects::RangeUnspecified, ColorAspects::PrimariesUnspecified,
1522                 ColorAspects::TransferUnspecified, ColorAspects::MatrixUnspecified
1523             };
1524             ColorUtils::getColorAspectsFromFormat(msg, aspects);
1525             ColorAspects origAspects = aspects;
1526             if (mUsingSurface) {
1527                 // get image size (default to HD)
1528                 int32_t width = 1280;
1529                 int32_t height = 720;
1530                 int32_t left, top, right, bottom;
1531                 if (msg->findRect("crop", &left, &top, &right, &bottom)) {
1532                     width = right - left + 1;
1533                     height = bottom - top + 1;
1534                 } else {
1535                     (void)msg->findInt32(KEY_WIDTH, &width);
1536                     (void)msg->findInt32(KEY_HEIGHT, &height);
1537                 }
1538                 ColorUtils::setDefaultCodecColorAspectsIfNeeded(aspects, width, height);
1539                 ColorUtils::setColorAspectsIntoFormat(aspects, msg);
1540             }
1541 
1542             if (!msg->findInt32("android._dataspace", (int32_t*)&dataspace)
1543                     || aspects.mRange != origAspects.mRange
1544                     || aspects.mPrimaries != origAspects.mPrimaries
1545                     || aspects.mTransfer != origAspects.mTransfer
1546                     || aspects.mMatrixCoeffs != origAspects.mMatrixCoeffs) {
1547                 dataspace = ColorUtils::getDataSpaceForColorAspects(aspects, true /* mayExpand */);
1548                 msg->setInt32("android._dataspace", dataspace);
1549             }
1550         }
1551 
1552         if (mInputSurface) {
1553             android_dataspace dataspace = mInputSurface->getDataspace();
1554             ColorUtils::convertDataSpaceToV0(dataspace);
1555             int32_t standard;
1556             ColorUtils::getColorConfigFromDataSpace(dataspace, &range, &standard, &transfer);
1557             if (range != 0) {
1558                 msg->setInt32(KEY_COLOR_RANGE, range);
1559             }
1560             if (standard != 0) {
1561                 msg->setInt32(KEY_COLOR_STANDARD, standard);
1562             }
1563             if (transfer != 0) {
1564                 msg->setInt32(KEY_COLOR_TRANSFER, transfer);
1565             }
1566             msg->setInt32("android._dataspace", dataspace);
1567         }
1568 
1569         // HDR static info
1570 
1571         C2HdrStaticMetadataStruct hdr;
1572         if (msg->findFloat("smpte2086.red.x", &hdr.mastering.red.x)
1573                 && msg->findFloat("smpte2086.red.y", &hdr.mastering.red.y)
1574                 && msg->findFloat("smpte2086.green.x", &hdr.mastering.green.x)
1575                 && msg->findFloat("smpte2086.green.y", &hdr.mastering.green.y)
1576                 && msg->findFloat("smpte2086.blue.x", &hdr.mastering.blue.x)
1577                 && msg->findFloat("smpte2086.blue.y", &hdr.mastering.blue.y)
1578                 && msg->findFloat("smpte2086.white.x", &hdr.mastering.white.x)
1579                 && msg->findFloat("smpte2086.white.y", &hdr.mastering.white.y)
1580                 && msg->findFloat("smpte2086.max-luminance", &hdr.mastering.maxLuminance)
1581                 && msg->findFloat("smpte2086.min-luminance", &hdr.mastering.minLuminance)
1582                 && msg->findFloat("cta861.max-cll", &hdr.maxCll)
1583                 && msg->findFloat("cta861.max-fall", &hdr.maxFall)) {
1584             if (hdr.mastering.red.x >= 0                && hdr.mastering.red.x <= 1
1585                     && hdr.mastering.red.y >= 0         && hdr.mastering.red.y <= 1
1586                     && hdr.mastering.green.x >= 0       && hdr.mastering.green.x <= 1
1587                     && hdr.mastering.green.y >= 0       && hdr.mastering.green.y <= 1
1588                     && hdr.mastering.blue.x >= 0        && hdr.mastering.blue.x <= 1
1589                     && hdr.mastering.blue.y >= 0        && hdr.mastering.blue.y <= 1
1590                     && hdr.mastering.white.x >= 0       && hdr.mastering.white.x <= 1
1591                     && hdr.mastering.white.y >= 0       && hdr.mastering.white.y <= 1
1592                     && hdr.mastering.maxLuminance >= 0  && hdr.mastering.maxLuminance <= 65535
1593                     && hdr.mastering.minLuminance >= 0  && hdr.mastering.minLuminance <= 6.5535
1594                     && hdr.maxCll >= 0                  && hdr.maxCll <= 65535
1595                     && hdr.maxFall >= 0                 && hdr.maxFall <= 65535) {
1596                 HDRStaticInfo meta;
1597                 meta.mID = meta.kType1;
1598                 meta.sType1.mR.x = hdr.mastering.red.x / 0.00002 + 0.5;
1599                 meta.sType1.mR.y = hdr.mastering.red.y / 0.00002 + 0.5;
1600                 meta.sType1.mG.x = hdr.mastering.green.x / 0.00002 + 0.5;
1601                 meta.sType1.mG.y = hdr.mastering.green.y / 0.00002 + 0.5;
1602                 meta.sType1.mB.x = hdr.mastering.blue.x / 0.00002 + 0.5;
1603                 meta.sType1.mB.y = hdr.mastering.blue.y / 0.00002 + 0.5;
1604                 meta.sType1.mW.x = hdr.mastering.white.x / 0.00002 + 0.5;
1605                 meta.sType1.mW.y = hdr.mastering.white.y / 0.00002 + 0.5;
1606                 meta.sType1.mMaxDisplayLuminance = hdr.mastering.maxLuminance + 0.5;
1607                 meta.sType1.mMinDisplayLuminance = hdr.mastering.minLuminance / 0.0001 + 0.5;
1608                 meta.sType1.mMaxContentLightLevel = hdr.maxCll + 0.5;
1609                 meta.sType1.mMaxFrameAverageLightLevel = hdr.maxFall + 0.5;
1610                 msg->setBuffer(KEY_HDR_STATIC_INFO, ABuffer::CreateAsCopy(&meta, sizeof(meta)));
1611             } else {
1612                 ALOGD("found invalid HDR static metadata %s", msg->debugString(8).c_str());
1613             }
1614             msg->removeEntryAt(msg->findEntryByName("smpte2086.red.x"));
1615             msg->removeEntryAt(msg->findEntryByName("smpte2086.red.y"));
1616             msg->removeEntryAt(msg->findEntryByName("smpte2086.green.x"));
1617             msg->removeEntryAt(msg->findEntryByName("smpte2086.green.y"));
1618             msg->removeEntryAt(msg->findEntryByName("smpte2086.blue.x"));
1619             msg->removeEntryAt(msg->findEntryByName("smpte2086.blue.y"));
1620             msg->removeEntryAt(msg->findEntryByName("smpte2086.white.x"));
1621             msg->removeEntryAt(msg->findEntryByName("smpte2086.white.y"));
1622             msg->removeEntryAt(msg->findEntryByName("smpte2086.max-luminance"));
1623             msg->removeEntryAt(msg->findEntryByName("smpte2086.min-luminance"));
1624             msg->removeEntryAt(msg->findEntryByName("cta861.max-cll"));
1625             msg->removeEntryAt(msg->findEntryByName("cta861.max-fall"));
1626         }
1627 
1628         // HDR dynamic info
1629         std::string keyPrefix = input ? C2_PARAMKEY_INPUT_HDR_DYNAMIC_INFO
1630                                       : C2_PARAMKEY_OUTPUT_HDR_DYNAMIC_INFO;
1631         std::string typeKey = keyPrefix + ".type";
1632         std::string dataKey = keyPrefix + ".data";
1633         int32_t type;
1634         sp<ABuffer> data;
1635         if (msg->findInt32(typeKey.c_str(), &type)
1636                 && msg->findBuffer(dataKey.c_str(), &data)) {
1637             if (type == HDR_DYNAMIC_METADATA_TYPE_SMPTE_2094_40) {
1638                 msg->setBuffer(KEY_HDR10_PLUS_INFO, data);
1639                 msg->removeEntryAt(msg->findEntryByName(typeKey.c_str()));
1640                 msg->removeEntryAt(msg->findEntryByName(dataKey.c_str()));
1641             }
1642         }
1643     }
1644 
1645     ALOGV("converted to SDK values as %s", msg->debugString().c_str());
1646     return msg;
1647 }
1648 
1649 /// converts an AMessage value to a ParamUpdater value
convert(const AMessage::ItemData & from,ReflectedParamUpdater::Value * to)1650 static void convert(const AMessage::ItemData &from, ReflectedParamUpdater::Value *to) {
1651     int32_t int32Value;
1652     int64_t int64Value;
1653     sp<ABuffer> bufValue;
1654     AString strValue;
1655     float floatValue;
1656     double doubleValue;
1657 
1658     if (from.find(&int32Value)) {
1659         to->set(int32Value);
1660     } else if (from.find(&int64Value)) {
1661         to->set(int64Value);
1662     } else if (from.find(&bufValue)) {
1663         to->set(bufValue);
1664     } else if (from.find(&strValue)) {
1665         to->set(strValue);
1666     } else if (from.find(&floatValue)) {
1667         to->set(C2Value(floatValue));
1668     } else if (from.find(&doubleValue)) {
1669         // convert double to float
1670         to->set(C2Value((float)doubleValue));
1671     }
1672     // ignore all other AMessage types
1673 }
1674 
1675 /// relaxes Codec 2.0 specific value types to SDK types (mainly removes signedness and counterness
1676 /// from 32/64-bit values.)
relaxValues(ReflectedParamUpdater::Value & item)1677 static void relaxValues(ReflectedParamUpdater::Value &item) {
1678     C2Value c2Value;
1679     int32_t int32Value;
1680     int64_t int64Value;
1681     (void)item.find(&c2Value);
1682     if (c2Value.get(&int32Value) || c2Value.get((uint32_t*)&int32Value)
1683             || c2Value.get((c2_cntr32_t*)&int32Value)) {
1684         item.set(int32Value);
1685     } else if (c2Value.get(&int64Value)
1686             || c2Value.get((uint64_t*)&int64Value)
1687             || c2Value.get((c2_cntr64_t*)&int64Value)) {
1688         item.set(int64Value);
1689     }
1690 }
1691 
getReflectedFormat(const sp<AMessage> & params_,Domain configDomain) const1692 ReflectedParamUpdater::Dict CCodecConfig::getReflectedFormat(
1693         const sp<AMessage> &params_, Domain configDomain) const {
1694     // create a modifiable copy of params
1695     sp<AMessage> params = params_->dup();
1696     ALOGV("filtering with config domain %x", configDomain);
1697 
1698     // convert some macro parameters to Codec 2.0 specific expressions
1699 
1700     { // make i-frame-interval frame based
1701         float iFrameInterval;
1702         if (params->findAsFloat(KEY_I_FRAME_INTERVAL, &iFrameInterval)) {
1703             float frameRate;
1704             if (params->findAsFloat(KEY_FRAME_RATE, &frameRate)) {
1705                 params->setInt32("i-frame-period",
1706                         (frameRate <= 0 || iFrameInterval < 0)
1707                                  ? -1 /* no sync frames */
1708                                  : (int32_t)c2_min(iFrameInterval * frameRate + 0.5,
1709                                                    (float)INT32_MAX));
1710             }
1711         }
1712     }
1713 
1714     if (mDomain == (IS_VIDEO | IS_ENCODER)) {
1715         // convert capture-rate into input-time-stretch
1716         float frameRate, captureRate;
1717         if (params->findAsFloat(KEY_FRAME_RATE, &frameRate)) {
1718             if (!params->findAsFloat("time-lapse-fps", &captureRate)
1719                     && !params->findAsFloat(KEY_CAPTURE_RATE, &captureRate)) {
1720                 captureRate = frameRate;
1721             }
1722             if (captureRate > 0 && frameRate > 0) {
1723                 params->setFloat(C2_PARAMKEY_INPUT_TIME_STRETCH, captureRate / frameRate);
1724             }
1725         }
1726 
1727         // add HDR format for video encoding
1728         if (configDomain == IS_CONFIG) {
1729             // don't assume here that transfer is set for HDR, only require it for HLG
1730             int transfer = 0;
1731             params->findInt32(KEY_COLOR_TRANSFER, &transfer);
1732 
1733             int profile;
1734             if (params->findInt32(KEY_PROFILE, &profile)) {
1735                 std::shared_ptr<C2Mapper::ProfileLevelMapper> mapper =
1736                     C2Mapper::GetProfileLevelMapper(mCodingMediaType);
1737                 C2Config::hdr_format_t c2 = C2Config::hdr_format_t::UNKNOWN;
1738                 if (mapper && mapper->mapHdrFormat(profile, &c2)) {
1739                     if (c2 == C2Config::hdr_format_t::HLG &&
1740                         transfer != COLOR_TRANSFER_HLG) {
1741                         c2 = C2Config::hdr_format_t::UNKNOWN;
1742                     }
1743                     params->setInt32(C2_PARAMKEY_HDR_FORMAT, c2);
1744                 }
1745             }
1746         }
1747     }
1748 
1749     {   // reflect temporal layering into a binary blob
1750         AString schema;
1751         if (params->findString(KEY_TEMPORAL_LAYERING, &schema)) {
1752             unsigned int numLayers = 0;
1753             unsigned int numBLayers = 0;
1754             int tags;
1755             char dummy;
1756             std::unique_ptr<C2StreamTemporalLayeringTuning::output> layering;
1757             if (sscanf(schema.c_str(), "webrtc.vp8.%u-layer%c", &numLayers, &dummy) == 1
1758                 && numLayers > 0) {
1759                 switch (numLayers) {
1760                     case 1:
1761                         layering = C2StreamTemporalLayeringTuning::output::AllocUnique(
1762                                 {}, 0u, 1u, 0u);
1763                         break;
1764                     case 2:
1765                         layering = C2StreamTemporalLayeringTuning::output::AllocUnique(
1766                                 { .6f }, 0u, 2u, 0u);
1767                         break;
1768                     case 3:
1769                         layering = C2StreamTemporalLayeringTuning::output::AllocUnique(
1770                                 { .4f, .6f }, 0u, 3u, 0u);
1771                         break;
1772                     default:
1773                         layering = C2StreamTemporalLayeringTuning::output::AllocUnique(
1774                                 { .25f, .4f, .6f }, 0u, 4u, 0u);
1775                         break;
1776                 }
1777             } else if ((tags = sscanf(schema.c_str(), "android.generic.%u%c%u%c",
1778                         &numLayers, &dummy, &numBLayers, &dummy))
1779                 && (tags == 1 || (tags == 3 && dummy == '+'))
1780                 && numLayers > 0 && numLayers < UINT32_MAX - numBLayers) {
1781                 layering = C2StreamTemporalLayeringTuning::output::AllocUnique(
1782                         {}, 0u, numLayers + numBLayers, numBLayers);
1783             } else {
1784                 ALOGD("Ignoring unsupported ts-schema [%s]", schema.c_str());
1785             }
1786             if (layering) {
1787                 params->setBuffer(C2_PARAMKEY_TEMPORAL_LAYERING,
1788                                   ABuffer::CreateAsCopy(layering.get(), layering->size()));
1789             }
1790         }
1791     }
1792 
1793     { // convert from MediaFormat rect to Codec 2.0 rect
1794         int32_t offset;
1795         int32_t end;
1796         AMessage::ItemData item;
1797         if (params->findInt32("crop-left", &offset) && params->findInt32("crop-right", &end)
1798                 && offset >= 0 && end >= offset - 1) {
1799             size_t ix = params->findEntryByName("crop-right");
1800             params->setEntryNameAt(ix, "crop-width");
1801             item.set(end - offset + 1);
1802             params->setEntryAt(ix, item);
1803         }
1804         if (params->findInt32("crop-top", &offset) && params->findInt32("crop-bottom", &end)
1805                 && offset >= 0 && end >= offset - 1) {
1806             size_t ix = params->findEntryByName("crop-bottom");
1807             params->setEntryNameAt(ix, "crop-height");
1808             item.set(end - offset + 1);
1809             params->setEntryAt(ix, item);
1810         }
1811     }
1812 
1813     { // convert color info
1814         int32_t standard;
1815         if (params->findInt32(KEY_COLOR_STANDARD, &standard)) {
1816             C2Color::primaries_t primaries;
1817             C2Color::matrix_t matrix;
1818 
1819             if (C2Mapper::map(standard, &primaries, &matrix)) {
1820                 params->setInt32("color-primaries", primaries);
1821                 params->setInt32("color-matrix", matrix);
1822             }
1823         }
1824 
1825         sp<ABuffer> hdrMeta;
1826         if (params->findBuffer(KEY_HDR_STATIC_INFO, &hdrMeta)
1827                 && hdrMeta->size() == sizeof(HDRStaticInfo)) {
1828             HDRStaticInfo *meta = (HDRStaticInfo*)hdrMeta->data();
1829             if (meta->mID == meta->kType1) {
1830                 params->setFloat("smpte2086.red.x", meta->sType1.mR.x * 0.00002);
1831                 params->setFloat("smpte2086.red.y", meta->sType1.mR.y * 0.00002);
1832                 params->setFloat("smpte2086.green.x", meta->sType1.mG.x * 0.00002);
1833                 params->setFloat("smpte2086.green.y", meta->sType1.mG.y * 0.00002);
1834                 params->setFloat("smpte2086.blue.x", meta->sType1.mB.x * 0.00002);
1835                 params->setFloat("smpte2086.blue.y", meta->sType1.mB.y * 0.00002);
1836                 params->setFloat("smpte2086.white.x", meta->sType1.mW.x * 0.00002);
1837                 params->setFloat("smpte2086.white.y", meta->sType1.mW.y * 0.00002);
1838                 params->setFloat("smpte2086.max-luminance", meta->sType1.mMaxDisplayLuminance);
1839                 params->setFloat("smpte2086.min-luminance", meta->sType1.mMinDisplayLuminance * 0.0001);
1840                 params->setFloat("cta861.max-cll", meta->sType1.mMaxContentLightLevel);
1841                 params->setFloat("cta861.max-fall", meta->sType1.mMaxFrameAverageLightLevel);
1842             }
1843         }
1844 
1845         sp<ABuffer> hdrDynamicInfo;
1846         if (params->findBuffer(KEY_HDR10_PLUS_INFO, &hdrDynamicInfo)) {
1847             for (const std::string &prefix : { C2_PARAMKEY_INPUT_HDR_DYNAMIC_INFO,
1848                                                C2_PARAMKEY_OUTPUT_HDR_DYNAMIC_INFO }) {
1849                 params->setInt32((prefix + ".type").c_str(),
1850                                  HDR_DYNAMIC_METADATA_TYPE_SMPTE_2094_40);
1851                 params->setBuffer((prefix + ".data").c_str(), hdrDynamicInfo);
1852             }
1853         }
1854     }
1855 
1856     // this is to verify that we set proper signedness for standard parameters
1857     bool beVeryStrict = property_get_bool("debug.stagefright.ccodec_strict_type", false);
1858     // this is to allow vendors to use the wrong signedness for standard parameters
1859     bool beVeryLax = property_get_bool("debug.stagefright.ccodec_lax_type", false);
1860 
1861     ReflectedParamUpdater::Dict filtered;
1862     for (size_t ix = 0; ix < params->countEntries(); ++ix) {
1863         AMessage::Type type;
1864         AString name = params->getEntryNameAt(ix, &type);
1865         AMessage::ItemData msgItem = params->getEntryAt(ix);
1866         ReflectedParamUpdater::Value item;
1867         convert(msgItem, &item); // convert item to param updater item
1868 
1869         if (name.startsWith("vendor.")) {
1870             // vendor params pass through as is
1871             filtered.emplace(name.c_str(), item);
1872             continue;
1873         }
1874         // standard parameters may get modified, filtered or duplicated
1875         for (const ConfigMapper &cm : mStandardParams->getConfigMappersForSdkKey(name.c_str())) {
1876             // note: we ignore port domain for configuration
1877             if ((cm.domain() & configDomain)
1878                     // component domain + kind (these must match)
1879                     && (cm.domain() & mDomain) == mDomain) {
1880                 // map arithmetic values, pass through string or buffer
1881                 switch (type) {
1882                     case AMessage::kTypeBuffer:
1883                     case AMessage::kTypeString:
1884                         break;
1885                     case AMessage::kTypeInt32:
1886                     case AMessage::kTypeInt64:
1887                     case AMessage::kTypeFloat:
1888                     case AMessage::kTypeDouble:
1889                         // for now only map settings with mappers as we are not creating
1890                         // signed <=> unsigned mappers
1891                         // TODO: be precise about signed unsigned
1892                         if (beVeryStrict || cm.mapper()) {
1893                             item.set(cm.mapFromMessage(params->getEntryAt(ix)));
1894                             // also allow to relax type strictness
1895                             if (beVeryLax) {
1896                                 relaxValues(item);
1897                             }
1898                         }
1899                         break;
1900                     default:
1901                         continue;
1902                 }
1903                 filtered.emplace(cm.path(), item);
1904             }
1905         }
1906     }
1907     ALOGV("filter src msg %s", params->debugString(4).c_str());
1908     ALOGV("filter dst params %s", filtered.debugString(4).c_str());
1909     return filtered;
1910 }
1911 
getConfigUpdateFromSdkParams(std::shared_ptr<Codec2Client::Configurable> configurable,const sp<AMessage> & sdkParams,Domain configDomain,c2_blocking_t blocking,std::vector<std::unique_ptr<C2Param>> * configUpdate) const1912 status_t CCodecConfig::getConfigUpdateFromSdkParams(
1913         std::shared_ptr<Codec2Client::Configurable> configurable,
1914         const sp<AMessage> &sdkParams, Domain configDomain,
1915         c2_blocking_t blocking,
1916         std::vector<std::unique_ptr<C2Param>> *configUpdate) const {
1917     ReflectedParamUpdater::Dict params = getReflectedFormat(sdkParams, configDomain);
1918 
1919     std::vector<C2Param::Index> indices;
1920     mParamUpdater->getParamIndicesFromMessage(params, &indices);
1921     if (indices.empty()) {
1922         ALOGD("no recognized params in: %s", params.debugString().c_str());
1923         return OK;
1924     }
1925 
1926     configUpdate->clear();
1927     std::vector<C2Param::Index> supportedIndices;
1928     for (C2Param::Index ix : indices) {
1929         if (mSupportedIndices.count(ix)) {
1930             supportedIndices.push_back(ix);
1931         } else if (mLocalParams.count(ix)) {
1932             // query local parameter here
1933             auto it = mCurrentConfig.find(ix);
1934             if (it != mCurrentConfig.end()) {
1935                 configUpdate->emplace_back(C2Param::Copy(*it->second));
1936             }
1937         }
1938     }
1939 
1940     c2_status_t err = configurable->query({ }, supportedIndices, blocking, configUpdate);
1941     if (err != C2_OK) {
1942         ALOGD("query failed after returning %zu params => %s", configUpdate->size(), asString(err));
1943     }
1944 
1945     if (configUpdate->size()) {
1946         mParamUpdater->updateParamsFromMessage(params, configUpdate);
1947     }
1948     return OK;
1949 }
1950 
setParameters(std::shared_ptr<Codec2Client::Configurable> configurable,std::vector<std::unique_ptr<C2Param>> & configUpdate,c2_blocking_t blocking)1951 status_t CCodecConfig::setParameters(
1952         std::shared_ptr<Codec2Client::Configurable> configurable,
1953         std::vector<std::unique_ptr<C2Param>> &configUpdate,
1954         c2_blocking_t blocking) {
1955     status_t result = OK;
1956     if (configUpdate.empty()) {
1957         return OK;
1958     }
1959 
1960     std::vector<C2Param::Index> indices;
1961     std::vector<C2Param *> paramVector;
1962     for (const std::unique_ptr<C2Param> &param : configUpdate) {
1963         if (mSupportedIndices.count(param->index())) {
1964             // component parameter
1965             paramVector.push_back(param.get());
1966             indices.push_back(param->index());
1967         } else if (mLocalParams.count(param->index())) {
1968             // handle local parameter here
1969             LocalParamValidator validator = mLocalParams.find(param->index())->second;
1970             c2_status_t err = C2_OK;
1971             std::unique_ptr<C2Param> copy = C2Param::Copy(*param);
1972             if (validator) {
1973                 err = validator(copy);
1974             }
1975             if (err == C2_OK) {
1976                 ALOGV("updated local parameter value for %s",
1977                         mParamUpdater->getParamName(param->index()).c_str());
1978 
1979                 mCurrentConfig[param->index()] = std::move(copy);
1980             } else {
1981                 ALOGD("failed to set parameter value for %s => %s",
1982                         mParamUpdater->getParamName(param->index()).c_str(), asString(err));
1983                 result = BAD_VALUE;
1984             }
1985         }
1986     }
1987     // update subscribed param indices
1988     subscribeToConfigUpdate(configurable, indices, blocking);
1989 
1990     std::vector<std::unique_ptr<C2SettingResult>> failures;
1991     c2_status_t err = configurable->config(paramVector, blocking, &failures);
1992     if (err != C2_OK) {
1993         ALOGD("config failed => %s", asString(err));
1994         // This is non-fatal.
1995     }
1996     for (const std::unique_ptr<C2SettingResult> &failure : failures) {
1997         switch (failure->failure) {
1998             case C2SettingResult::BAD_VALUE:
1999                 ALOGD("Bad parameter value");
2000                 result = BAD_VALUE;
2001                 break;
2002             default:
2003                 ALOGV("failure = %d", int(failure->failure));
2004                 break;
2005         }
2006     }
2007 
2008     // Re-query parameter values in case config could not update them and update the current
2009     // configuration.
2010     configUpdate.clear();
2011     err = configurable->query({}, indices, blocking, &configUpdate);
2012     if (err != C2_OK) {
2013         ALOGD("query failed after returning %zu params => %s", configUpdate.size(), asString(err));
2014     }
2015     (void)updateConfiguration(configUpdate, ALL);
2016 
2017     // TODO: error value
2018     return result;
2019 }
2020 
getConfigParameterValue(C2Param::Index index) const2021 const C2Param *CCodecConfig::getConfigParameterValue(C2Param::Index index) const {
2022     auto it = mCurrentConfig.find(index);
2023     if (it == mCurrentConfig.end()) {
2024         return nullptr;
2025     } else {
2026         return it->second.get();
2027     }
2028 }
2029 
subscribeToAllVendorParams(const std::shared_ptr<Codec2Client::Configurable> & configurable,c2_blocking_t blocking)2030 status_t CCodecConfig::subscribeToAllVendorParams(
2031         const std::shared_ptr<Codec2Client::Configurable> &configurable,
2032         c2_blocking_t blocking) {
2033     for (const auto &[path, desc] : mVendorParams) {
2034         mSubscribedIndices.insert(desc->index());
2035     }
2036     return subscribeToConfigUpdate(configurable, {}, blocking);
2037 }
2038 
querySupportedParameters(std::vector<std::string> * names)2039 status_t CCodecConfig::querySupportedParameters(std::vector<std::string> *names) {
2040     if (!names) {
2041         return BAD_VALUE;
2042     }
2043     names->clear();
2044     // TODO: expand to standard params
2045     for (const auto &[key, desc] : mVendorParams) {
2046         if (desc->isVisible()) {
2047             names->push_back(key);
2048         }
2049     }
2050     return OK;
2051 }
2052 
describe(const std::string & name,CodecParameterDescriptor * desc)2053 status_t CCodecConfig::describe(const std::string &name, CodecParameterDescriptor *desc) {
2054     if (!desc) {
2055         return BAD_VALUE;
2056     }
2057     // TODO: expand to standard params
2058     desc->name = name;
2059     switch (mParamUpdater->getTypeForKey(name)) {
2060         case C2FieldDescriptor::INT32:
2061         case C2FieldDescriptor::UINT32:
2062         case C2FieldDescriptor::CNTR32:
2063             desc->type = AMessage::kTypeInt32;
2064             return OK;
2065         case C2FieldDescriptor::INT64:
2066         case C2FieldDescriptor::UINT64:
2067         case C2FieldDescriptor::CNTR64:
2068             desc->type = AMessage::kTypeInt64;
2069             return OK;
2070         case C2FieldDescriptor::FLOAT:
2071             desc->type = AMessage::kTypeFloat;
2072             return OK;
2073         case C2FieldDescriptor::STRING:
2074             desc->type = AMessage::kTypeString;
2075             return OK;
2076         case C2FieldDescriptor::BLOB:
2077             desc->type = AMessage::kTypeBuffer;
2078             return OK;
2079         default:
2080             return NAME_NOT_FOUND;
2081     }
2082 }
2083 
subscribeToVendorConfigUpdate(const std::shared_ptr<Codec2Client::Configurable> & configurable,const std::vector<std::string> & names,c2_blocking_t blocking)2084 status_t CCodecConfig::subscribeToVendorConfigUpdate(
2085         const std::shared_ptr<Codec2Client::Configurable> &configurable,
2086         const std::vector<std::string> &names,
2087         c2_blocking_t blocking) {
2088     for (const std::string &name : names) {
2089         auto it = mVendorParams.find(name);
2090         if (it == mVendorParams.end()) {
2091             ALOGD("%s is not a recognized vendor parameter; ignored.", name.c_str());
2092             continue;
2093         }
2094         mSubscribedIndices.insert(it->second->index());
2095     }
2096     return subscribeToConfigUpdate(configurable, {}, blocking);
2097 }
2098 
unsubscribeFromVendorConfigUpdate(const std::shared_ptr<Codec2Client::Configurable> & configurable,const std::vector<std::string> & names,c2_blocking_t blocking)2099 status_t CCodecConfig::unsubscribeFromVendorConfigUpdate(
2100         const std::shared_ptr<Codec2Client::Configurable> &configurable,
2101         const std::vector<std::string> &names,
2102         c2_blocking_t blocking) {
2103     for (const std::string &name : names) {
2104         auto it = mVendorParams.find(name);
2105         if (it == mVendorParams.end()) {
2106             ALOGD("%s is not a recognized vendor parameter; ignored.", name.c_str());
2107             continue;
2108         }
2109         mSubscribedIndices.erase(it->second->index());
2110     }
2111     return subscribeToConfigUpdate(configurable, {}, blocking);
2112 }
2113 
2114 }  // namespace android
2115