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 #include <cutils/properties.h>
20 #include <log/log.h>
21 
22 #include <C2Component.h>
23 #include <C2Debug.h>
24 #include <C2Param.h>
25 #include <util/C2InterfaceHelper.h>
26 
27 #include <media/stagefright/MediaCodecConstants.h>
28 
29 #include "CCodecConfig.h"
30 #include "Codec2Mapper.h"
31 
32 #define DRC_DEFAULT_MOBILE_REF_LEVEL 64  /* 64*-0.25dB = -16 dB below full scale for mobile conf */
33 #define DRC_DEFAULT_MOBILE_DRC_CUT   127 /* maximum compression of dynamic range for mobile conf */
34 #define DRC_DEFAULT_MOBILE_DRC_BOOST 127 /* maximum compression of dynamic range for mobile conf */
35 #define DRC_DEFAULT_MOBILE_DRC_HEAVY 1   /* switch for heavy compression for mobile conf */
36 #define DRC_DEFAULT_MOBILE_DRC_EFFECT 3  /* MPEG-D DRC effect type; 3 => Limited playback range */
37 #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) */
38 // names of properties that can be used to override the default DRC settings
39 #define PROP_DRC_OVERRIDE_REF_LEVEL  "aac_drc_reference_level"
40 #define PROP_DRC_OVERRIDE_CUT        "aac_drc_cut"
41 #define PROP_DRC_OVERRIDE_BOOST      "aac_drc_boost"
42 #define PROP_DRC_OVERRIDE_HEAVY      "aac_drc_heavy"
43 #define PROP_DRC_OVERRIDE_ENC_LEVEL  "aac_drc_enc_target_level"
44 #define PROP_DRC_OVERRIDE_EFFECT     "ro.aac_drc_effect_type"
45 
46 namespace android {
47 
48 // CCodecConfig
49 
50 namespace {
51 
52 /**
53  * mapping between SDK and Codec 2.0 configurations.
54  */
55 struct ConfigMapper {
56     /**
57      * Value mapper (C2Value => C2Value)
58      */
59     typedef std::function<C2Value(C2Value)> Mapper;
60 
61     /// shorthand
62     typedef CCodecConfig::Domain Domain;
63 
ConfigMapperandroid::__anon5f9fd7420111::ConfigMapper64     ConfigMapper(std::string mediaKey, C2String c2struct, C2String c2field)
65         : mDomain(Domain::ALL), mMediaKey(mediaKey), mStruct(c2struct), mField(c2field) { }
66 
67     /// Limits this parameter to the given domain
limitToandroid::__anon5f9fd7420111::ConfigMapper68     ConfigMapper &limitTo(uint32_t domain) {
69         C2_CHECK(domain & Domain::GUARD_BIT);
70         mDomain = Domain(mDomain & domain);
71         return *this;
72     }
73 
74     /// Adds SDK => Codec 2.0 mapper (should not be in the SDK format)
withMapperandroid::__anon5f9fd7420111::ConfigMapper75     ConfigMapper &withMapper(Mapper mapper) {
76         C2_CHECK(!mMapper);
77         C2_CHECK(!mReverse);
78         mMapper = mapper;
79         return *this;
80     }
81 
82     /// Adds SDK <=> Codec 2.0 value mappers
withMappersandroid::__anon5f9fd7420111::ConfigMapper83     ConfigMapper &withMappers(Mapper mapper, Mapper reverse) {
84         C2_CHECK(!mMapper);
85         C2_CHECK(!mReverse);
86         mMapper = mapper;
87         mReverse = reverse;
88         return *this;
89     }
90 
91     /// Adds SDK <=> Codec 2.0 value mappers based on C2Mapper
92     template<typename C2Type, typename SdkType=int32_t>
withC2Mappersandroid::__anon5f9fd7420111::ConfigMapper93     ConfigMapper &withC2Mappers() {
94         C2_CHECK(!mMapper);
95         C2_CHECK(!mReverse);
96         mMapper = [](C2Value v) -> C2Value {
97             SdkType sdkValue;
98             C2Type c2Value;
99             if (v.get(&sdkValue) && C2Mapper::map(sdkValue, &c2Value)) {
100                 return c2Value;
101             }
102             return C2Value();
103         };
104         mReverse = [](C2Value v) -> C2Value {
105             SdkType sdkValue;
106             C2Type c2Value;
107             using C2ValueType=typename _c2_reduce_enum_to_underlying_type<C2Type>::type;
108             if (v.get((C2ValueType*)&c2Value) && C2Mapper::map(c2Value, &sdkValue)) {
109                 return sdkValue;
110             }
111             return C2Value();
112         };
113         return *this;
114     }
115 
116     /// Maps from SDK values in an AMessage to a suitable C2Value.
mapFromMessageandroid::__anon5f9fd7420111::ConfigMapper117     C2Value mapFromMessage(const AMessage::ItemData &item) const {
118         C2Value value;
119         int32_t int32Value;
120         int64_t int64Value;
121         float floatValue;
122         double doubleValue;
123         if (item.find(&int32Value)) {
124             value = int32Value;
125         } else if (item.find(&int64Value)) {
126             value = int64Value;
127         } else if (item.find(&floatValue)) {
128             value = floatValue;
129         } else if (item.find(&doubleValue)) {
130             value = (float)doubleValue;
131         }
132         if (value.type() != C2Value::NO_INIT && mMapper) {
133             value = mMapper(value);
134         }
135         return value;
136     }
137 
138     /// Maps from a C2Value to an SDK value in an AMessage.
mapToMessageandroid::__anon5f9fd7420111::ConfigMapper139     AMessage::ItemData mapToMessage(C2Value value) const {
140         AMessage::ItemData item;
141         int32_t int32Value;
142         uint32_t uint32Value;
143         int64_t int64Value;
144         uint64_t uint64Value;
145         float floatValue;
146         if (value.type() != C2Value::NO_INIT && mReverse) {
147             value = mReverse(value);
148         }
149         if (value.get(&int32Value)) {
150             item.set(int32Value);
151         } else if (value.get(&uint32Value) && uint32Value <= uint32_t(INT32_MAX)) {
152             // SDK does not support unsigned values
153             item.set((int32_t)uint32Value);
154         } else if (value.get(&int64Value)) {
155             item.set(int64Value);
156         } else if (value.get(&uint64Value) && uint64Value <= uint64_t(INT64_MAX)) {
157             // SDK does not support unsigned values
158             item.set((int64_t)uint64Value);
159         } else if (value.get(&floatValue)) {
160             item.set(floatValue);
161         }
162         return item;
163     }
164 
domainandroid::__anon5f9fd7420111::ConfigMapper165     Domain domain() const { return mDomain; }
mediaKeyandroid::__anon5f9fd7420111::ConfigMapper166     std::string mediaKey() const { return mMediaKey; }
pathandroid::__anon5f9fd7420111::ConfigMapper167     std::string path() const { return mField.size() ? mStruct + '.' + mField : mStruct; }
mapperandroid::__anon5f9fd7420111::ConfigMapper168     Mapper mapper() const { return mMapper; }
reverseandroid::__anon5f9fd7420111::ConfigMapper169     Mapper reverse() const { return mReverse; }
170 
171 private:
172     Domain mDomain;         ///< parameter domain (mask) containing port, kind and config domains
173     std::string mMediaKey;  ///< SDK key
174     C2String mStruct;       ///< Codec 2.0 struct name
175     C2String mField;        ///< Codec 2.0 field name
176     Mapper mMapper;         ///< optional SDK => Codec 2.0 value mapper
177     Mapper mReverse;        ///< optional Codec 2.0 => SDK value mapper
178 };
179 
180 template <typename PORT, typename STREAM>
QueryMediaTypeImpl(const std::shared_ptr<Codec2Client::Component> & component)181 AString QueryMediaTypeImpl(
182         const std::shared_ptr<Codec2Client::Component> &component) {
183     AString mediaType;
184     std::vector<std::unique_ptr<C2Param>> queried;
185     c2_status_t c2err = component->query(
186             {}, { PORT::PARAM_TYPE, STREAM::PARAM_TYPE }, C2_DONT_BLOCK, &queried);
187     if (c2err != C2_OK && queried.size() == 0) {
188         ALOGD("Query media type failed => %s", asString(c2err));
189     } else {
190         PORT *portMediaType =
191             PORT::From(queried[0].get());
192         if (portMediaType) {
193             mediaType = AString(
194                     portMediaType->m.value,
195                     strnlen(portMediaType->m.value, portMediaType->flexCount()));
196         } else {
197             STREAM *streamMediaType = STREAM::From(queried[0].get());
198             if (streamMediaType) {
199                 mediaType = AString(
200                         streamMediaType->m.value,
201                         strnlen(streamMediaType->m.value, streamMediaType->flexCount()));
202             }
203         }
204         ALOGD("read media type: %s", mediaType.c_str());
205     }
206     return mediaType;
207 }
208 
QueryMediaType(bool input,const std::shared_ptr<Codec2Client::Component> & component)209 AString QueryMediaType(
210         bool input, const std::shared_ptr<Codec2Client::Component> &component) {
211     typedef C2PortMediaTypeSetting P;
212     typedef C2StreamMediaTypeSetting S;
213     if (input) {
214         return QueryMediaTypeImpl<P::input, S::input>(component);
215     } else {
216         return QueryMediaTypeImpl<P::output, S::output>(component);
217     }
218 }
219 
220 }  // namespace
221 
222 /**
223  * Set of standard parameters used by CCodec that are exposed to MediaCodec.
224  */
225 struct StandardParams {
226     typedef CCodecConfig::Domain Domain;
227 
228     // standard (MediaCodec) params are keyed by media format key
229     typedef std::string SdkKey;
230 
231     /// used to return reference to no config mappers in getConfigMappersForSdkKey
232     static const std::vector<ConfigMapper> NO_MAPPERS;
233 
234     /// Returns Codec 2.0 equivalent parameters for an SDK format key.
getConfigMappersForSdkKeyandroid::StandardParams235     const std::vector<ConfigMapper> &getConfigMappersForSdkKey(std::string key) const {
236         auto it = mConfigMappers.find(key);
237         if (it == mConfigMappers.end()) {
238             if (mComplained.count(key) == 0) {
239                 ALOGD("no c2 equivalents for %s", key.c_str());
240                 mComplained.insert(key);
241             }
242             return NO_MAPPERS;
243         }
244         ALOGV("found %zu eqs for %s", it->second.size(), key.c_str());
245         return it->second;
246     }
247 
248     /**
249      * Adds a SDK <=> Codec 2.0 parameter mapping. Multiple Codec 2.0 parameters may map to a
250      * single SDK key, in which case they shall be ordered from least authoritative to most
251      * authoritative. When constructing SDK formats, the last mapped Codec 2.0 parameter that
252      * is supported by the component will determine the exposed value. (TODO: perhaps restrict this
253      * by domain.)
254      */
addandroid::StandardParams255     void add(const ConfigMapper &cm) {
256         auto it = mConfigMappers.find(cm.mediaKey());
257         ALOGV("%c%c%c%c %c%c%c %04x %9s %s => %s",
258               ((cm.domain() & Domain::IS_INPUT) ? 'I' : ' '),
259               ((cm.domain() & Domain::IS_OUTPUT) ? 'O' : ' '),
260               ((cm.domain() & Domain::IS_CODED) ? 'C' : ' '),
261               ((cm.domain() & Domain::IS_RAW) ? 'R' : ' '),
262               ((cm.domain() & Domain::IS_CONFIG) ? 'c' : ' '),
263               ((cm.domain() & Domain::IS_PARAM) ? 'p' : ' '),
264               ((cm.domain() & Domain::IS_READ) ? 'r' : ' '),
265               cm.domain(),
266               it == mConfigMappers.end() ? "adding" : "extending",
267               cm.mediaKey().c_str(), cm.path().c_str());
268         if (it == mConfigMappers.end()) {
269             std::vector<ConfigMapper> eqs = { cm };
270             mConfigMappers.emplace(cm.mediaKey(), eqs);
271         } else {
272             it->second.push_back(cm);
273         }
274     }
275 
276     /**
277      * Returns all paths for a specific domain.
278      *
279      * \param any maximum domain mask. Returned parameters must match at least one of the domains
280      *            in the mask.
281      * \param all minimum domain mask. Returned parameters must match all of the domains in the
282      *            mask. This is restricted to the bits of the maximum mask.
283      */
getPathsForDomainandroid::StandardParams284     std::vector<std::string> getPathsForDomain(
285             Domain any, Domain all = Domain::ALL) const {
286         std::vector<std::string> res;
287         for (const std::pair<std::string, std::vector<ConfigMapper>> &el : mConfigMappers) {
288             for (const ConfigMapper &cm : el.second) {
289                 ALOGV("filtering %s %x %x %x %x", cm.path().c_str(), cm.domain(), any,
290                         (cm.domain() & any), (cm.domain() & any & all));
291                 if ((cm.domain() & any) && ((cm.domain() & any & all) == (any & all))) {
292                     res.push_back(cm.path());
293                 }
294             }
295         }
296         return res;
297     }
298 
299     /**
300      * Returns SDK <=> Codec 2.0 mappings.
301      *
302      * TODO: replace these with better methods as this exposes the inner structure.
303      */
getKeysandroid::StandardParams304     const std::map<SdkKey, std::vector<ConfigMapper>> getKeys() const {
305         return mConfigMappers;
306     }
307 
308 private:
309     std::map<SdkKey, std::vector<ConfigMapper>> mConfigMappers;
310     mutable std::set<std::string> mComplained;
311 };
312 
313 const std::vector<ConfigMapper> StandardParams::NO_MAPPERS;
314 
315 
CCodecConfig()316 CCodecConfig::CCodecConfig()
317     : mInputFormat(new AMessage),
318       mOutputFormat(new AMessage),
319       mUsingSurface(false) { }
320 
initializeStandardParams()321 void CCodecConfig::initializeStandardParams() {
322     typedef Domain D;
323     mStandardParams = std::make_shared<StandardParams>();
324     std::function<void(const ConfigMapper &)> add =
325         [params = mStandardParams](const ConfigMapper &cm) {
326             params->add(cm);
327     };
328     std::function<void(const ConfigMapper &)> deprecated = add;
329 
330     // allow int32 or float SDK values and represent them as float
331     ConfigMapper::Mapper makeFloat = [](C2Value v) -> C2Value {
332         // convert from i32 to float
333         int32_t i32Value;
334         float fpValue;
335         if (v.get(&i32Value)) {
336             return (float)i32Value;
337         } else if (v.get(&fpValue)) {
338             return fpValue;
339         }
340         return C2Value();
341     };
342 
343     ConfigMapper::Mapper negate = [](C2Value v) -> C2Value {
344         int32_t value;
345         if (v.get(&value)) {
346             return -value;
347         }
348         return C2Value();
349     };
350 
351     add(ConfigMapper(KEY_MIME,     C2_PARAMKEY_INPUT_MEDIA_TYPE,    "value")
352         .limitTo(D::INPUT & D::READ));
353     add(ConfigMapper(KEY_MIME,     C2_PARAMKEY_OUTPUT_MEDIA_TYPE,   "value")
354         .limitTo(D::OUTPUT & D::READ));
355 
356     add(ConfigMapper(KEY_BIT_RATE, C2_PARAMKEY_BITRATE, "value")
357         .limitTo(D::ENCODER & D::OUTPUT));
358     // we also need to put the bitrate in the max bitrate field
359     add(ConfigMapper(KEY_MAX_BIT_RATE, C2_PARAMKEY_BITRATE, "value")
360         .limitTo(D::ENCODER & D::READ & D::OUTPUT));
361     add(ConfigMapper(PARAMETER_KEY_VIDEO_BITRATE, C2_PARAMKEY_BITRATE, "value")
362         .limitTo(D::ENCODER & D::VIDEO & D::PARAM));
363     add(ConfigMapper(KEY_BITRATE_MODE, C2_PARAMKEY_BITRATE_MODE, "value")
364         .limitTo(D::ENCODER & D::CODED)
365         .withC2Mappers<C2Config::bitrate_mode_t>());
366     // remove when codecs switch to PARAMKEY and new modes
367     deprecated(ConfigMapper(KEY_BITRATE_MODE, "coded.bitrate-mode", "value")
368                .limitTo(D::ENCODER));
369     add(ConfigMapper(KEY_FRAME_RATE, C2_PARAMKEY_FRAME_RATE, "value")
370         .limitTo(D::VIDEO)
371         .withMappers(makeFloat, [](C2Value v) -> C2Value {
372             // read back always as int
373             float value;
374             if (v.get(&value)) {
375                 return (int32_t)value;
376             }
377             return C2Value();
378         }));
379 
380     add(ConfigMapper(KEY_MAX_INPUT_SIZE, C2_PARAMKEY_INPUT_MAX_BUFFER_SIZE, "value")
381         .limitTo(D::INPUT));
382     // remove when codecs switch to PARAMKEY
383     deprecated(ConfigMapper(KEY_MAX_INPUT_SIZE, "coded.max-frame-size", "value")
384                .limitTo(D::INPUT));
385 
386     // Rotation
387     // Note: SDK rotation is clock-wise, while C2 rotation is counter-clock-wise
388     add(ConfigMapper(KEY_ROTATION, C2_PARAMKEY_VUI_ROTATION, "value")
389         .limitTo(D::VIDEO & D::CODED)
390         .withMappers(negate, negate));
391     add(ConfigMapper(KEY_ROTATION, C2_PARAMKEY_ROTATION, "value")
392         .limitTo(D::VIDEO & D::RAW)
393         .withMappers(negate, negate));
394 
395     // android 'video-scaling'
396     add(ConfigMapper("android._video-scaling", C2_PARAMKEY_SURFACE_SCALING_MODE, "value")
397         .limitTo(D::VIDEO & D::DECODER & D::RAW));
398 
399     // Color Aspects
400     //
401     // configure default for decoders
402     add(ConfigMapper(KEY_COLOR_RANGE,       C2_PARAMKEY_DEFAULT_COLOR_ASPECTS,   "range")
403         .limitTo((D::VIDEO | D::IMAGE) & D::DECODER  & D::CODED & (D::CONFIG | D::PARAM))
404         .withC2Mappers<C2Color::range_t>());
405     add(ConfigMapper(KEY_COLOR_TRANSFER,    C2_PARAMKEY_DEFAULT_COLOR_ASPECTS,   "transfer")
406         .limitTo((D::VIDEO | D::IMAGE) & D::DECODER  & D::CODED & (D::CONFIG | D::PARAM))
407         .withC2Mappers<C2Color::transfer_t>());
408     add(ConfigMapper("color-primaries",     C2_PARAMKEY_DEFAULT_COLOR_ASPECTS,   "primaries")
409         .limitTo((D::VIDEO | D::IMAGE) & D::DECODER  & D::CODED & (D::CONFIG | D::PARAM)));
410     add(ConfigMapper("color-matrix",        C2_PARAMKEY_DEFAULT_COLOR_ASPECTS,   "matrix")
411         .limitTo((D::VIDEO | D::IMAGE) & D::DECODER  & D::CODED & (D::CONFIG | D::PARAM)));
412 
413     // read back final for decoder output (also, configure final aspects as well. This should be
414     // overwritten based on coded/default values if component supports color aspects, but is used
415     // as final values if component does not support aspects at all)
416     add(ConfigMapper(KEY_COLOR_RANGE,       C2_PARAMKEY_COLOR_ASPECTS,   "range")
417         .limitTo((D::VIDEO | D::IMAGE) & D::DECODER  & D::RAW)
418         .withC2Mappers<C2Color::range_t>());
419     add(ConfigMapper(KEY_COLOR_TRANSFER,    C2_PARAMKEY_COLOR_ASPECTS,   "transfer")
420         .limitTo((D::VIDEO | D::IMAGE) & D::DECODER  & D::RAW)
421         .withC2Mappers<C2Color::transfer_t>());
422     add(ConfigMapper("color-primaries",     C2_PARAMKEY_COLOR_ASPECTS,   "primaries")
423         .limitTo((D::VIDEO | D::IMAGE) & D::DECODER  & D::RAW));
424     add(ConfigMapper("color-matrix",        C2_PARAMKEY_COLOR_ASPECTS,   "matrix")
425         .limitTo((D::VIDEO | D::IMAGE) & D::DECODER  & D::RAW));
426 
427     // configure source aspects for encoders and read them back on the coded(!) port.
428     // This is to ensure muxing the desired aspects into the container.
429     add(ConfigMapper(KEY_COLOR_RANGE,       C2_PARAMKEY_COLOR_ASPECTS,   "range")
430         .limitTo((D::VIDEO | D::IMAGE) & D::ENCODER  & D::CODED)
431         .withC2Mappers<C2Color::range_t>());
432     add(ConfigMapper(KEY_COLOR_TRANSFER,    C2_PARAMKEY_COLOR_ASPECTS,   "transfer")
433         .limitTo((D::VIDEO | D::IMAGE) & D::ENCODER  & D::CODED)
434         .withC2Mappers<C2Color::transfer_t>());
435     add(ConfigMapper("color-primaries",     C2_PARAMKEY_COLOR_ASPECTS,   "primaries")
436         .limitTo((D::VIDEO | D::IMAGE) & D::ENCODER  & D::CODED));
437     add(ConfigMapper("color-matrix",        C2_PARAMKEY_COLOR_ASPECTS,   "matrix")
438         .limitTo((D::VIDEO | D::IMAGE) & D::ENCODER  & D::CODED));
439 
440     // read back coded aspects for encoders (on the raw port), but also configure
441     // desired aspects here.
442     add(ConfigMapper(KEY_COLOR_RANGE,       C2_PARAMKEY_VUI_COLOR_ASPECTS,   "range")
443         .limitTo((D::VIDEO | D::IMAGE) & D::ENCODER  & D::RAW)
444         .withC2Mappers<C2Color::range_t>());
445     add(ConfigMapper(KEY_COLOR_TRANSFER,    C2_PARAMKEY_VUI_COLOR_ASPECTS,   "transfer")
446         .limitTo((D::VIDEO | D::IMAGE) & D::ENCODER  & D::RAW)
447         .withC2Mappers<C2Color::transfer_t>());
448     add(ConfigMapper("color-primaries",     C2_PARAMKEY_VUI_COLOR_ASPECTS,   "primaries")
449         .limitTo((D::VIDEO | D::IMAGE) & D::ENCODER  & D::RAW));
450     add(ConfigMapper("color-matrix",        C2_PARAMKEY_VUI_COLOR_ASPECTS,   "matrix")
451         .limitTo((D::VIDEO | D::IMAGE) & D::ENCODER  & D::RAW));
452 
453     // Dataspace
454     add(ConfigMapper("android._dataspace", C2_PARAMKEY_DATA_SPACE, "value")
455         .limitTo((D::VIDEO | D::IMAGE) & D::RAW));
456 
457     // HDR
458     add(ConfigMapper("smpte2086.red.x", C2_PARAMKEY_HDR_STATIC_INFO, "mastering.red.x")
459         .limitTo((D::VIDEO | D::IMAGE) & D::RAW));
460     add(ConfigMapper("smpte2086.red.y", C2_PARAMKEY_HDR_STATIC_INFO, "mastering.red.y")
461         .limitTo((D::VIDEO | D::IMAGE) & D::RAW));
462     add(ConfigMapper("smpte2086.green.x", C2_PARAMKEY_HDR_STATIC_INFO, "mastering.green.x")
463         .limitTo((D::VIDEO | D::IMAGE) & D::RAW));
464     add(ConfigMapper("smpte2086.green.y", C2_PARAMKEY_HDR_STATIC_INFO, "mastering.green.y")
465         .limitTo((D::VIDEO | D::IMAGE) & D::RAW));
466     add(ConfigMapper("smpte2086.blue.x", C2_PARAMKEY_HDR_STATIC_INFO, "mastering.blue.x")
467         .limitTo((D::VIDEO | D::IMAGE) & D::RAW));
468     add(ConfigMapper("smpte2086.blue.y", C2_PARAMKEY_HDR_STATIC_INFO, "mastering.blue.y")
469         .limitTo((D::VIDEO | D::IMAGE) & D::RAW));
470     add(ConfigMapper("smpte2086.white.x", C2_PARAMKEY_HDR_STATIC_INFO, "mastering.white.x")
471         .limitTo((D::VIDEO | D::IMAGE) & D::RAW));
472     add(ConfigMapper("smpte2086.white.y", C2_PARAMKEY_HDR_STATIC_INFO, "mastering.white.y")
473         .limitTo((D::VIDEO | D::IMAGE) & D::RAW));
474     add(ConfigMapper("smpte2086.max-luminance", C2_PARAMKEY_HDR_STATIC_INFO, "mastering.max-luminance")
475         .limitTo((D::VIDEO | D::IMAGE) & D::RAW));
476     add(ConfigMapper("smpte2086.min-luminance", C2_PARAMKEY_HDR_STATIC_INFO, "mastering.min-luminance")
477         .limitTo((D::VIDEO | D::IMAGE) & D::RAW));
478     add(ConfigMapper("cta861.max-cll", C2_PARAMKEY_HDR_STATIC_INFO, "max-cll")
479         .limitTo((D::VIDEO | D::IMAGE) & D::RAW));
480     add(ConfigMapper("cta861.max-fall", C2_PARAMKEY_HDR_STATIC_INFO, "max-fall")
481         .limitTo((D::VIDEO | D::IMAGE) & D::RAW));
482 
483     add(ConfigMapper(std::string(KEY_FEATURE_) + FEATURE_SecurePlayback,
484                      C2_PARAMKEY_SECURE_MODE, "value"));
485 
486     add(ConfigMapper(KEY_PREPEND_HEADERS_TO_SYNC_FRAMES,
487                      C2_PARAMKEY_PREPEND_HEADER_MODE, "value")
488         .limitTo(D::ENCODER & D::VIDEO)
489         .withMappers([](C2Value v) -> C2Value {
490             int32_t value;
491             if (v.get(&value)) {
492                 return value ? C2Value(C2Config::PREPEND_HEADER_TO_ALL_SYNC)
493                              : C2Value(C2Config::PREPEND_HEADER_TO_NONE);
494             }
495             return C2Value();
496         }, [](C2Value v) -> C2Value {
497             C2Config::prepend_header_mode_t value;
498             using C2ValueType=typename _c2_reduce_enum_to_underlying_type<decltype(value)>::type;
499             if (v.get((C2ValueType *)&value)) {
500                 switch (value) {
501                     case C2Config::PREPEND_HEADER_TO_NONE:      return 0;
502                     case C2Config::PREPEND_HEADER_TO_ALL_SYNC:  return 1;
503                     case C2Config::PREPEND_HEADER_ON_CHANGE:    [[fallthrough]];
504                     default:                                    return C2Value();
505                 }
506             }
507             return C2Value();
508         }));
509     // remove when codecs switch to PARAMKEY
510     deprecated(ConfigMapper(KEY_PREPEND_HEADERS_TO_SYNC_FRAMES,
511                             "coding.add-csd-to-sync-frames", "value")
512                .limitTo(D::ENCODER & D::VIDEO));
513     // convert to timestamp base
514     add(ConfigMapper(KEY_I_FRAME_INTERVAL, C2_PARAMKEY_SYNC_FRAME_INTERVAL, "value")
515         .limitTo(D::VIDEO & D::ENCODER & D::CONFIG)
516         .withMapper([](C2Value v) -> C2Value {
517             // convert from i32 to float
518             int32_t i32Value;
519             float fpValue;
520             if (v.get(&i32Value)) {
521                 return int64_t(1000000) * i32Value;
522             } else if (v.get(&fpValue)) {
523                 return int64_t(c2_min(1000000 * fpValue + 0.5, (double)INT64_MAX));
524             }
525             return C2Value();
526         }));
527     // remove when codecs switch to proper coding.gop (add support for calculating gop)
528     deprecated(ConfigMapper("i-frame-period", "coding.gop", "intra-period")
529                .limitTo(D::ENCODER & D::VIDEO));
530     add(ConfigMapper(KEY_INTRA_REFRESH_PERIOD, C2_PARAMKEY_INTRA_REFRESH, "period")
531         .limitTo(D::VIDEO & D::ENCODER)
532         .withMappers(makeFloat, [](C2Value v) -> C2Value {
533             // read back always as int
534             float value;
535             if (v.get(&value)) {
536                 return (int32_t)value;
537             }
538             return C2Value();
539         }));
540     deprecated(ConfigMapper(PARAMETER_KEY_REQUEST_SYNC_FRAME,
541                      "coding.request-sync", "value")
542         .limitTo(D::PARAM & D::ENCODER)
543         .withMapper([](C2Value) -> C2Value { return uint32_t(1); }));
544     add(ConfigMapper(PARAMETER_KEY_REQUEST_SYNC_FRAME,
545                      C2_PARAMKEY_REQUEST_SYNC_FRAME, "value")
546         .limitTo(D::PARAM & D::ENCODER)
547         .withMapper([](C2Value) -> C2Value { return uint32_t(1); }));
548 
549     add(ConfigMapper(KEY_OPERATING_RATE,   C2_PARAMKEY_OPERATING_RATE,     "value")
550         .limitTo(D::PARAM | D::CONFIG) // write-only
551         .withMapper(makeFloat));
552     // C2 priorities are inverted
553     add(ConfigMapper(KEY_PRIORITY,         C2_PARAMKEY_PRIORITY,           "value")
554         .withMappers(negate, negate));
555     // remove when codecs switch to PARAMKEY
556     deprecated(ConfigMapper(KEY_OPERATING_RATE,   "ctrl.operating-rate",     "value")
557                .withMapper(makeFloat));
558     deprecated(ConfigMapper(KEY_PRIORITY,         "ctrl.priority",           "value"));
559 
560     add(ConfigMapper(KEY_WIDTH,         C2_PARAMKEY_PICTURE_SIZE,       "width")
561         .limitTo(D::VIDEO | D::IMAGE));
562     add(ConfigMapper(KEY_HEIGHT,        C2_PARAMKEY_PICTURE_SIZE,       "height")
563         .limitTo(D::VIDEO | D::IMAGE));
564 
565     add(ConfigMapper("crop-left",       C2_PARAMKEY_CROP_RECT,       "left")
566         .limitTo(D::VIDEO | D::IMAGE));
567     add(ConfigMapper("crop-top",        C2_PARAMKEY_CROP_RECT,       "top")
568         .limitTo(D::VIDEO | D::IMAGE));
569     add(ConfigMapper("crop-width",      C2_PARAMKEY_CROP_RECT,       "width")
570         .limitTo(D::VIDEO | D::IMAGE));
571     add(ConfigMapper("crop-height",     C2_PARAMKEY_CROP_RECT,       "height")
572         .limitTo(D::VIDEO | D::IMAGE));
573 
574     add(ConfigMapper(KEY_MAX_WIDTH,     C2_PARAMKEY_MAX_PICTURE_SIZE,    "width")
575         .limitTo((D::VIDEO | D::IMAGE) & D::RAW));
576     add(ConfigMapper(KEY_MAX_HEIGHT,    C2_PARAMKEY_MAX_PICTURE_SIZE,    "height")
577         .limitTo((D::VIDEO | D::IMAGE) & D::RAW));
578 
579     add(ConfigMapper("csd-0",           C2_PARAMKEY_INIT_DATA,       "value")
580         .limitTo(D::OUTPUT & D::READ));
581 
582     add(ConfigMapper(KEY_HDR10_PLUS_INFO, C2_PARAMKEY_INPUT_HDR10_PLUS_INFO, "value")
583         .limitTo(D::VIDEO & D::PARAM & D::INPUT));
584 
585     add(ConfigMapper(KEY_HDR10_PLUS_INFO, C2_PARAMKEY_OUTPUT_HDR10_PLUS_INFO, "value")
586         .limitTo(D::VIDEO & D::OUTPUT));
587 
588     add(ConfigMapper(C2_PARAMKEY_TEMPORAL_LAYERING, C2_PARAMKEY_TEMPORAL_LAYERING, "")
589         .limitTo(D::ENCODER & D::VIDEO & D::OUTPUT));
590 
591     // Pixel Format (use local key for actual pixel format as we don't distinguish between
592     // SDK layouts for flexible format and we need the actual SDK color format in the media format)
593     add(ConfigMapper("android._color-format",  C2_PARAMKEY_PIXEL_FORMAT, "value")
594         .limitTo((D::VIDEO | D::IMAGE) & D::RAW)
595         .withMappers([](C2Value v) -> C2Value {
596             int32_t value;
597             if (v.get(&value)) {
598                 switch (value) {
599                     case COLOR_FormatSurface:
600                         return (uint32_t)HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED;
601                     case COLOR_FormatYUV420Flexible:
602                         return (uint32_t)HAL_PIXEL_FORMAT_YCBCR_420_888;
603                     case COLOR_FormatYUV420Planar:
604                     case COLOR_FormatYUV420SemiPlanar:
605                     case COLOR_FormatYUV420PackedPlanar:
606                     case COLOR_FormatYUV420PackedSemiPlanar:
607                         return (uint32_t)HAL_PIXEL_FORMAT_YV12;
608                     default:
609                         // TODO: support some sort of passthrough
610                         break;
611                 }
612             }
613             return C2Value();
614         }, [](C2Value v) -> C2Value {
615             uint32_t value;
616             if (v.get(&value)) {
617                 switch (value) {
618                     case HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED:
619                         return COLOR_FormatSurface;
620                     case HAL_PIXEL_FORMAT_YV12:
621                     case HAL_PIXEL_FORMAT_YCBCR_420_888:
622                         return COLOR_FormatYUV420Flexible;
623                     default:
624                         // TODO: support some sort of passthrough
625                         break;
626                 }
627             }
628             return C2Value();
629         }));
630 
631     add(ConfigMapper(KEY_CHANNEL_COUNT, C2_PARAMKEY_CHANNEL_COUNT,       "value")
632         .limitTo(D::AUDIO)); // read back to both formats
633     add(ConfigMapper(KEY_CHANNEL_COUNT, C2_PARAMKEY_CODED_CHANNEL_COUNT, "value")
634         .limitTo(D::AUDIO & D::CODED));
635 
636     add(ConfigMapper(KEY_SAMPLE_RATE,   C2_PARAMKEY_SAMPLE_RATE,        "value")
637         .limitTo(D::AUDIO)); // read back to both port formats
638     add(ConfigMapper(KEY_SAMPLE_RATE,   C2_PARAMKEY_CODED_SAMPLE_RATE,  "value")
639         .limitTo(D::AUDIO & D::CODED));
640 
641     add(ConfigMapper(KEY_PCM_ENCODING,  C2_PARAMKEY_PCM_ENCODING,       "value")
642         .limitTo(D::AUDIO)
643         .withMappers([](C2Value v) -> C2Value {
644             int32_t value;
645             C2Config::pcm_encoding_t to;
646             if (v.get(&value) && C2Mapper::map(value, &to)) {
647                 return to;
648             }
649             return C2Value();
650         }, [](C2Value v) -> C2Value {
651             C2Config::pcm_encoding_t value;
652             int32_t to;
653             using C2ValueType=typename _c2_reduce_enum_to_underlying_type<decltype(value)>::type;
654             if (v.get((C2ValueType*)&value) && C2Mapper::map(value, &to)) {
655                 return to;
656             }
657             return C2Value();
658         }));
659 
660     add(ConfigMapper(KEY_IS_ADTS, C2_PARAMKEY_AAC_PACKAGING, "value")
661         .limitTo(D::AUDIO & D::CODED)
662         .withMappers([](C2Value v) -> C2Value {
663             int32_t value;
664             if (v.get(&value) && value) {
665                 return C2Config::AAC_PACKAGING_ADTS;
666             }
667             return C2Value();
668         }, [](C2Value v) -> C2Value {
669             uint32_t value;
670             if (v.get(&value) && value == C2Config::AAC_PACKAGING_ADTS) {
671                 return (int32_t)1;
672             }
673             return C2Value();
674         }));
675 
676     std::shared_ptr<C2Mapper::ProfileLevelMapper> mapper =
677         C2Mapper::GetProfileLevelMapper(mCodingMediaType);
678 
679     add(ConfigMapper(KEY_PROFILE, C2_PARAMKEY_PROFILE_LEVEL, "profile")
680         .limitTo(D::CODED)
681         .withMappers([mapper](C2Value v) -> C2Value {
682             C2Config::profile_t c2 = PROFILE_UNUSED;
683             int32_t sdk;
684             if (mapper && v.get(&sdk) && mapper->mapProfile(sdk, &c2)) {
685                 return c2;
686             }
687             return PROFILE_UNUSED;
688         }, [mapper](C2Value v) -> C2Value {
689             C2Config::profile_t c2;
690             int32_t sdk;
691             using C2ValueType=typename _c2_reduce_enum_to_underlying_type<decltype(c2)>::type;
692             if (mapper && v.get((C2ValueType*)&c2) && mapper->mapProfile(c2, &sdk)) {
693                 return sdk;
694             }
695             return C2Value();
696         }));
697 
698     add(ConfigMapper(KEY_LEVEL, C2_PARAMKEY_PROFILE_LEVEL, "level")
699         .limitTo(D::CODED)
700         .withMappers([mapper](C2Value v) -> C2Value {
701             C2Config::level_t c2 = LEVEL_UNUSED;
702             int32_t sdk;
703             if (mapper && v.get(&sdk) && mapper->mapLevel(sdk, &c2)) {
704                 return c2;
705             }
706             return LEVEL_UNUSED;
707         }, [mapper](C2Value v) -> C2Value {
708             C2Config::level_t c2;
709             int32_t sdk;
710             using C2ValueType=typename _c2_reduce_enum_to_underlying_type<decltype(c2)>::type;
711             if (mapper && v.get((C2ValueType*)&c2) && mapper->mapLevel(c2, &sdk)) {
712                 return sdk;
713             }
714             return C2Value();
715         }));
716 
717     // convert to dBFS and add default
718     add(ConfigMapper(KEY_AAC_DRC_TARGET_REFERENCE_LEVEL, C2_PARAMKEY_DRC_TARGET_REFERENCE_LEVEL, "value")
719         .limitTo(D::AUDIO & D::DECODER & D::CONFIG)
720         .withMapper([](C2Value v) -> C2Value {
721             int32_t value;
722             if (!v.get(&value) || value < 0) {
723                 value = property_get_int32(PROP_DRC_OVERRIDE_REF_LEVEL, DRC_DEFAULT_MOBILE_REF_LEVEL);
724             }
725             return float(-0.25 * c2_min(value, 127));
726         }));
727 
728     // convert to 0-1 (%) and add default
729     add(ConfigMapper(KEY_AAC_DRC_ATTENUATION_FACTOR, C2_PARAMKEY_DRC_ATTENUATION_FACTOR, "value")
730         .limitTo(D::AUDIO & D::DECODER & D::CONFIG)
731         .withMapper([](C2Value v) -> C2Value {
732             int32_t value;
733             if (!v.get(&value) || value < 0) {
734                 value = property_get_int32(PROP_DRC_OVERRIDE_CUT, DRC_DEFAULT_MOBILE_DRC_CUT);
735             }
736             return float(c2_min(value, 127) / 127.);
737         }));
738 
739     // convert to 0-1 (%) and add default
740     add(ConfigMapper(KEY_AAC_DRC_BOOST_FACTOR, C2_PARAMKEY_DRC_BOOST_FACTOR, "value")
741         .limitTo(D::AUDIO & D::DECODER & D::CONFIG)
742         .withMapper([](C2Value v) -> C2Value {
743             int32_t value;
744             if (!v.get(&value) || value < 0) {
745                 value = property_get_int32(PROP_DRC_OVERRIDE_BOOST, DRC_DEFAULT_MOBILE_DRC_BOOST);
746             }
747             return float(c2_min(value, 127) / 127.);
748         }));
749 
750     // convert to compression type and add default
751     add(ConfigMapper(KEY_AAC_DRC_HEAVY_COMPRESSION, C2_PARAMKEY_DRC_COMPRESSION_MODE, "value")
752         .limitTo(D::AUDIO & D::DECODER & D::CONFIG)
753         .withMapper([](C2Value v) -> C2Value {
754             int32_t value;
755             if (!v.get(&value) || value < 0) {
756                 value = property_get_int32(PROP_DRC_OVERRIDE_HEAVY, DRC_DEFAULT_MOBILE_DRC_HEAVY);
757             }
758             return value == 1 ? C2Config::DRC_COMPRESSION_HEAVY : C2Config::DRC_COMPRESSION_LIGHT;
759         }));
760 
761     // convert to dBFS and add default
762     add(ConfigMapper(KEY_AAC_ENCODED_TARGET_LEVEL, C2_PARAMKEY_DRC_ENCODED_TARGET_LEVEL, "value")
763         .limitTo(D::AUDIO & D::DECODER & D::CONFIG)
764         .withMapper([](C2Value v) -> C2Value {
765             int32_t value;
766             if (!v.get(&value) || value < 0) {
767                 value = property_get_int32(PROP_DRC_OVERRIDE_ENC_LEVEL, DRC_DEFAULT_MOBILE_ENC_LEVEL);
768             }
769             return float(-0.25 * c2_min(value, 127));
770         }));
771 
772     // convert to effect type (these map to SDK values) and add default
773     add(ConfigMapper(KEY_AAC_DRC_EFFECT_TYPE, C2_PARAMKEY_DRC_EFFECT_TYPE, "value")
774         .limitTo(D::AUDIO & D::DECODER & D::CONFIG)
775         .withMapper([](C2Value v) -> C2Value {
776             int32_t value;
777             if (!v.get(&value) || value < -1 || value > 8) {
778                 value = property_get_int32(PROP_DRC_OVERRIDE_EFFECT, DRC_DEFAULT_MOBILE_DRC_EFFECT);
779                 // ensure value is within range
780                 if (value < -1 || value > 8) {
781                     value = DRC_DEFAULT_MOBILE_DRC_EFFECT;
782                 }
783             }
784             return value;
785         }));
786 
787     add(ConfigMapper(KEY_AAC_MAX_OUTPUT_CHANNEL_COUNT, C2_PARAMKEY_MAX_CHANNEL_COUNT, "value")
788         .limitTo(D::AUDIO));
789 
790     add(ConfigMapper(KEY_AAC_SBR_MODE, C2_PARAMKEY_AAC_SBR_MODE, "value")
791         .limitTo(D::AUDIO & D::ENCODER & D::CONFIG)
792         .withMapper([](C2Value v) -> C2Value {
793             int32_t value;
794             if (!v.get(&value) || value < 0) {
795                 return C2Config::AAC_SBR_AUTO;
796             }
797             switch (value) {
798                 case 0: return C2Config::AAC_SBR_OFF;
799                 case 1: return C2Config::AAC_SBR_SINGLE_RATE;
800                 case 2: return C2Config::AAC_SBR_DUAL_RATE;
801                 default: return C2Config::AAC_SBR_AUTO + 1; // invalid value
802             }
803         }));
804 
805     add(ConfigMapper(KEY_QUALITY, C2_PARAMKEY_QUALITY, "value")
806         .limitTo(D::ENCODER & (D::CONFIG | D::PARAM)));
807     add(ConfigMapper(KEY_FLAC_COMPRESSION_LEVEL, C2_PARAMKEY_COMPLEXITY, "value")
808         .limitTo(D::AUDIO & D::ENCODER));
809     add(ConfigMapper("complexity", C2_PARAMKEY_COMPLEXITY, "value")
810         .limitTo(D::ENCODER & (D::CONFIG | D::PARAM)));
811 
812     add(ConfigMapper(KEY_GRID_COLUMNS, C2_PARAMKEY_TILE_LAYOUT, "columns")
813         .limitTo(D::IMAGE));
814     add(ConfigMapper(KEY_GRID_ROWS, C2_PARAMKEY_TILE_LAYOUT, "rows")
815         .limitTo(D::IMAGE));
816     add(ConfigMapper(KEY_TILE_WIDTH, C2_PARAMKEY_TILE_LAYOUT, "tile.width")
817         .limitTo(D::IMAGE));
818     add(ConfigMapper(KEY_TILE_HEIGHT, C2_PARAMKEY_TILE_LAYOUT, "tile.height")
819         .limitTo(D::IMAGE));
820 
821     add(ConfigMapper(KEY_LATENCY, C2_PARAMKEY_PIPELINE_DELAY_REQUEST, "value")
822         .limitTo(D::VIDEO & D::ENCODER));
823 
824     add(ConfigMapper(C2_PARAMKEY_INPUT_TIME_STRETCH, C2_PARAMKEY_INPUT_TIME_STRETCH, "value"));
825 
826     /* still to do
827     constexpr char KEY_PUSH_BLANK_BUFFERS_ON_STOP[] = "push-blank-buffers-on-shutdown";
828 
829        not yet used by MediaCodec, but defined as MediaFormat
830     KEY_AUDIO_SESSION_ID // we use "audio-hw-sync"
831     KEY_OUTPUT_REORDER_DEPTH
832     */
833 }
834 
initialize(const std::shared_ptr<Codec2Client> & client,const std::shared_ptr<Codec2Client::Component> & component)835 status_t CCodecConfig::initialize(
836         const std::shared_ptr<Codec2Client> &client,
837         const std::shared_ptr<Codec2Client::Component> &component) {
838     C2ComponentDomainSetting domain(C2Component::DOMAIN_OTHER);
839     C2ComponentKindSetting kind(C2Component::KIND_OTHER);
840 
841     std::vector<std::unique_ptr<C2Param>> queried;
842     c2_status_t c2err = component->query({ &domain, &kind }, {}, C2_DONT_BLOCK, &queried);
843     if (c2err != C2_OK) {
844         ALOGD("Query domain & kind failed => %s", asString(c2err));
845         // TEMP: determine kind from component name
846         if (kind.value == C2Component::KIND_OTHER) {
847             if (component->getName().find("encoder") != std::string::npos) {
848                 kind.value = C2Component::KIND_ENCODER;
849             } else if (component->getName().find("decoder") != std::string::npos) {
850                 kind.value = C2Component::KIND_DECODER;
851             }
852         }
853 
854         // TEMP: determine domain from media type (port (preferred) or stream #0)
855         if (domain.value == C2Component::DOMAIN_OTHER) {
856             AString mediaType = QueryMediaType(true /* input */, component);
857             if (mediaType.startsWith("audio/")) {
858                 domain.value = C2Component::DOMAIN_AUDIO;
859             } else if (mediaType.startsWith("video/")) {
860                 domain.value = C2Component::DOMAIN_VIDEO;
861             } else if (mediaType.startsWith("image/")) {
862                 domain.value = C2Component::DOMAIN_IMAGE;
863             }
864         }
865     }
866 
867     mDomain = (domain.value == C2Component::DOMAIN_VIDEO ? Domain::IS_VIDEO :
868                domain.value == C2Component::DOMAIN_IMAGE ? Domain::IS_IMAGE :
869                domain.value == C2Component::DOMAIN_AUDIO ? Domain::IS_AUDIO : Domain::OTHER_DOMAIN)
870             | (kind.value == C2Component::KIND_DECODER ? Domain::IS_DECODER :
871                kind.value == C2Component::KIND_ENCODER ? Domain::IS_ENCODER : Domain::OTHER_KIND);
872 
873     mInputDomain = Domain(((mDomain & IS_DECODER) ? IS_CODED : IS_RAW) | IS_INPUT);
874     mOutputDomain = Domain(((mDomain & IS_ENCODER) ? IS_CODED : IS_RAW) | IS_OUTPUT);
875 
876     ALOGV("domain is %#x (%u %u)", mDomain, domain.value, kind.value);
877 
878     std::vector<C2Param::Index> paramIndices;
879     switch (kind.value) {
880     case C2Component::KIND_DECODER:
881         mCodingMediaType = QueryMediaType(true /* input */, component).c_str();
882         break;
883     case C2Component::KIND_ENCODER:
884         mCodingMediaType = QueryMediaType(false /* input */, component).c_str();
885         break;
886     default:
887         mCodingMediaType = "";
888     }
889 
890     c2err = component->querySupportedParams(&mParamDescs);
891     if (c2err != C2_OK) {
892         ALOGD("Query supported params failed after returning %zu values => %s",
893                 mParamDescs.size(), asString(c2err));
894         return UNKNOWN_ERROR;
895     }
896     for (const std::shared_ptr<C2ParamDescriptor> &desc : mParamDescs) {
897         mSupportedIndices.emplace(desc->index());
898     }
899 
900     mReflector = client->getParamReflector();
901     if (mReflector == nullptr) {
902         ALOGE("Failed to get param reflector");
903         return UNKNOWN_ERROR;
904     }
905 
906     // enumerate all fields
907     mParamUpdater = std::make_shared<ReflectedParamUpdater>();
908     mParamUpdater->clear();
909     mParamUpdater->supportWholeParam(
910             C2_PARAMKEY_TEMPORAL_LAYERING, C2StreamTemporalLayeringTuning::CORE_INDEX);
911     mParamUpdater->addParamDesc(mReflector, mParamDescs);
912 
913     // TEMP: add some standard fields even if not reflected
914     if (kind.value == C2Component::KIND_ENCODER) {
915         mParamUpdater->addStandardParam<C2StreamInitDataInfo::output>(C2_PARAMKEY_INIT_DATA);
916     }
917     if (domain.value == C2Component::DOMAIN_IMAGE || domain.value == C2Component::DOMAIN_VIDEO) {
918         if (kind.value != C2Component::KIND_ENCODER) {
919             addLocalParam<C2StreamPictureSizeInfo::output>(C2_PARAMKEY_PICTURE_SIZE);
920             addLocalParam<C2StreamCropRectInfo::output>(C2_PARAMKEY_CROP_RECT);
921             addLocalParam(
922                     new C2StreamPixelAspectRatioInfo::output(0u, 1u, 1u),
923                     C2_PARAMKEY_PIXEL_ASPECT_RATIO);
924             addLocalParam(new C2StreamRotationInfo::output(0u, 0), C2_PARAMKEY_ROTATION);
925             addLocalParam(new C2StreamColorAspectsInfo::output(0u), C2_PARAMKEY_COLOR_ASPECTS);
926             addLocalParam<C2StreamDataSpaceInfo::output>(C2_PARAMKEY_DATA_SPACE);
927             addLocalParam<C2StreamHdrStaticInfo::output>(C2_PARAMKEY_HDR_STATIC_INFO);
928             addLocalParam(new C2StreamSurfaceScalingInfo::output(0u, VIDEO_SCALING_MODE_SCALE_TO_FIT),
929                           C2_PARAMKEY_SURFACE_SCALING_MODE);
930         } else {
931             addLocalParam(new C2StreamColorAspectsInfo::input(0u), C2_PARAMKEY_COLOR_ASPECTS);
932         }
933     }
934 
935     initializeStandardParams();
936 
937     // subscribe to all supported standard (exposed) params
938     // TODO: limit this to params that are actually in the domain
939     std::vector<std::string> formatKeys = mStandardParams->getPathsForDomain(Domain(1 << 30));
940     std::vector<C2Param::Index> indices;
941     mParamUpdater->getParamIndicesForKeys(formatKeys, &indices);
942     mSubscribedIndices.insert(indices.begin(), indices.end());
943 
944     // also subscribe to some non-SDK standard parameters
945     // for number of input/output buffers
946     mSubscribedIndices.emplace(C2PortSuggestedBufferCountTuning::input::PARAM_TYPE);
947     mSubscribedIndices.emplace(C2PortSuggestedBufferCountTuning::output::PARAM_TYPE);
948     mSubscribedIndices.emplace(C2ActualPipelineDelayTuning::PARAM_TYPE);
949     mSubscribedIndices.emplace(C2PortActualDelayTuning::input::PARAM_TYPE);
950     mSubscribedIndices.emplace(C2PortActualDelayTuning::output::PARAM_TYPE);
951     // for output buffer array allocation
952     mSubscribedIndices.emplace(C2StreamMaxBufferSizeInfo::output::PARAM_TYPE);
953     // init data (CSD)
954     mSubscribedIndices.emplace(C2StreamInitDataInfo::output::PARAM_TYPE);
955 
956     return OK;
957 }
958 
subscribeToConfigUpdate(const std::shared_ptr<Codec2Client::Component> & component,const std::vector<C2Param::Index> & indices,c2_blocking_t blocking)959 status_t CCodecConfig::subscribeToConfigUpdate(
960         const std::shared_ptr<Codec2Client::Component> &component,
961         const std::vector<C2Param::Index> &indices,
962         c2_blocking_t blocking) {
963     mSubscribedIndices.insert(indices.begin(), indices.end());
964     // TODO: enable this when components no longer crash on this config
965     if (mSubscribedIndices.size() != mSubscribedIndicesSize && false) {
966         std::vector<uint32_t> indices;
967         for (C2Param::Index ix : mSubscribedIndices) {
968             indices.push_back(ix);
969         }
970         std::unique_ptr<C2SubscribedParamIndicesTuning> subscribeTuning =
971             C2SubscribedParamIndicesTuning::AllocUnique(indices);
972         std::vector<std::unique_ptr<C2SettingResult>> results;
973         c2_status_t c2Err = component->config({ subscribeTuning.get() }, blocking, &results);
974         if (c2Err != C2_OK && c2Err != C2_BAD_INDEX) {
975             ALOGD("Failed to subscribe to parameters => %s", asString(c2Err));
976             // TODO: error
977         }
978         ALOGV("Subscribed to %zu params", mSubscribedIndices.size());
979         mSubscribedIndicesSize = mSubscribedIndices.size();
980     }
981     return OK;
982 }
983 
queryConfiguration(const std::shared_ptr<Codec2Client::Component> & component)984 status_t CCodecConfig::queryConfiguration(
985         const std::shared_ptr<Codec2Client::Component> &component) {
986     // query all subscribed parameters
987     std::vector<C2Param::Index> indices(mSubscribedIndices.begin(), mSubscribedIndices.end());
988     std::vector<std::unique_ptr<C2Param>> queried;
989     c2_status_t c2Err = component->query({}, indices, C2_MAY_BLOCK, &queried);
990     if (c2Err != OK) {
991         ALOGI("query failed after returning %zu values (%s)", queried.size(), asString(c2Err));
992         // TODO: error
993     }
994 
995     updateConfiguration(queried, ALL);
996     return OK;
997 }
998 
updateConfiguration(std::vector<std::unique_ptr<C2Param>> & configUpdate,Domain domain)999 bool CCodecConfig::updateConfiguration(
1000         std::vector<std::unique_ptr<C2Param>> &configUpdate, Domain domain) {
1001     ALOGV("updating configuration with %zu params", configUpdate.size());
1002     bool changed = false;
1003     for (std::unique_ptr<C2Param> &p : configUpdate) {
1004         if (p && *p) {
1005             auto insertion = mCurrentConfig.emplace(p->index(), nullptr);
1006             if (insertion.second || *insertion.first->second != *p) {
1007                 if (mSupportedIndices.count(p->index()) || mLocalParams.count(p->index())) {
1008                     // only track changes in supported (reflected or local) indices
1009                     changed = true;
1010                 } else {
1011                     ALOGV("an unlisted config was %s: %#x",
1012                             insertion.second ? "added" : "updated", p->index());
1013                 }
1014             }
1015             insertion.first->second = std::move(p);
1016         }
1017     }
1018 
1019     ALOGV("updated configuration has %zu params (%s)", mCurrentConfig.size(),
1020             changed ? "CHANGED" : "no change");
1021     if (changed) {
1022         return updateFormats(domain);
1023     }
1024     return false;
1025 }
1026 
updateFormats(Domain domain)1027 bool CCodecConfig::updateFormats(Domain domain) {
1028     // get addresses of params in the current config
1029     std::vector<C2Param*> paramPointers;
1030     for (const auto &it : mCurrentConfig) {
1031         paramPointers.push_back(it.second.get());
1032     }
1033 
1034     ReflectedParamUpdater::Dict reflected = mParamUpdater->getParams(paramPointers);
1035     std::string config = reflected.debugString();
1036     std::set<std::string> configLines;
1037     std::string diff;
1038     for (size_t start = 0; start != std::string::npos; ) {
1039         size_t end = config.find('\n', start);
1040         size_t count = (end == std::string::npos)
1041                 ? std::string::npos
1042                 : end - start + 1;
1043         std::string line = config.substr(start, count);
1044         configLines.insert(line);
1045         if (mLastConfig.count(line) == 0) {
1046             diff.append(line);
1047         }
1048         start = (end == std::string::npos) ? std::string::npos : end + 1;
1049     }
1050     if (!diff.empty()) {
1051         ALOGD("c2 config diff is %s", diff.c_str());
1052     }
1053     mLastConfig.swap(configLines);
1054 
1055     bool changed = false;
1056     if (domain & mInputDomain) {
1057         sp<AMessage> oldFormat = mInputFormat;
1058         mInputFormat = mInputFormat->dup(); // trigger format changed
1059         mInputFormat->extend(getSdkFormatForDomain(reflected, mInputDomain));
1060         if (mInputFormat->countEntries() != oldFormat->countEntries()
1061                 || mInputFormat->changesFrom(oldFormat)->countEntries() > 0) {
1062             changed = true;
1063         } else {
1064             mInputFormat = oldFormat; // no change
1065         }
1066     }
1067     if (domain & mOutputDomain) {
1068         sp<AMessage> oldFormat = mOutputFormat;
1069         mOutputFormat = mOutputFormat->dup(); // trigger output format changed
1070         mOutputFormat->extend(getSdkFormatForDomain(reflected, mOutputDomain));
1071         if (mOutputFormat->countEntries() != oldFormat->countEntries()
1072                 || mOutputFormat->changesFrom(oldFormat)->countEntries() > 0) {
1073             changed = true;
1074         } else {
1075             mOutputFormat = oldFormat; // no change
1076         }
1077     }
1078     ALOGV_IF(changed, "format(s) changed");
1079     return changed;
1080 }
1081 
getSdkFormatForDomain(const ReflectedParamUpdater::Dict & reflected,Domain portDomain) const1082 sp<AMessage> CCodecConfig::getSdkFormatForDomain(
1083         const ReflectedParamUpdater::Dict &reflected, Domain portDomain) const {
1084     sp<AMessage> msg = new AMessage;
1085     for (const std::pair<std::string, std::vector<ConfigMapper>> &el : mStandardParams->getKeys()) {
1086         for (const ConfigMapper &cm : el.second) {
1087             if ((cm.domain() & portDomain) == 0 // input-output-coded-raw
1088                 || (cm.domain() & mDomain) != mDomain // component domain + kind (these must match)
1089                 || (cm.domain() & IS_READ) == 0) {
1090                 continue;
1091             }
1092             auto it = reflected.find(cm.path());
1093             if (it == reflected.end()) {
1094                 continue;
1095             }
1096             C2Value c2Value;
1097             sp<ABuffer> bufValue;
1098             AString strValue;
1099             AMessage::ItemData item;
1100             if (it->second.find(&c2Value)) {
1101                 item = cm.mapToMessage(c2Value);
1102             } else if (it->second.find(&bufValue)) {
1103                 item.set(bufValue);
1104             } else if (it->second.find(&strValue)) {
1105                 item.set(strValue);
1106             } else {
1107                 ALOGD("unexpected untyped query value for key: %s", cm.path().c_str());
1108                 continue;
1109             }
1110             msg->setItem(el.first.c_str(), item);
1111         }
1112     }
1113 
1114     { // convert from Codec 2.0 rect to MediaFormat rect and add crop rect if not present
1115         int32_t left, top, width, height;
1116         if (msg->findInt32("crop-left", &left) && msg->findInt32("crop-width", &width)
1117                 && msg->findInt32("crop-top", &top) && msg->findInt32("crop-height", &height)
1118                 && left >= 0 && width >=0 && width <= INT32_MAX - left
1119                 && top >= 0 && height >=0 && height <= INT32_MAX - top) {
1120             msg->removeEntryAt(msg->findEntryByName("crop-left"));
1121             msg->removeEntryAt(msg->findEntryByName("crop-top"));
1122             msg->removeEntryAt(msg->findEntryByName("crop-width"));
1123             msg->removeEntryAt(msg->findEntryByName("crop-height"));
1124             msg->setRect("crop", left, top, left + width - 1, top + height - 1);
1125         } else if (msg->findInt32("width", &width) && msg->findInt32("height", &height)) {
1126             msg->setRect("crop", 0, 0, width - 1, height - 1);
1127         }
1128     }
1129 
1130     { // convert temporal layering to schema
1131         sp<ABuffer> tmp;
1132         if (msg->findBuffer(C2_PARAMKEY_TEMPORAL_LAYERING, &tmp) && tmp != nullptr) {
1133             C2StreamTemporalLayeringTuning *layering =
1134                 C2StreamTemporalLayeringTuning::From(C2Param::From(tmp->data(), tmp->size()));
1135             if (layering && layering->m.layerCount > 0
1136                     && layering->m.bLayerCount < layering->m.layerCount) {
1137                 // check if this is webrtc compatible
1138                 AString mime;
1139                 if (msg->findString(KEY_MIME, &mime) &&
1140                         mime.equalsIgnoreCase(MIMETYPE_VIDEO_VP8) &&
1141                         layering->m.bLayerCount == 0 &&
1142                         (layering->m.layerCount == 1
1143                                 || (layering->m.layerCount == 2
1144                                         && layering->flexCount() >= 1
1145                                         && layering->m.bitrateRatios[0] == .6f)
1146                                 || (layering->m.layerCount == 3
1147                                         && layering->flexCount() >= 2
1148                                         && layering->m.bitrateRatios[0] == .4f
1149                                         && layering->m.bitrateRatios[1] == .6f)
1150                                 || (layering->m.layerCount == 4
1151                                         && layering->flexCount() >= 3
1152                                         && layering->m.bitrateRatios[0] == .25f
1153                                         && layering->m.bitrateRatios[1] == .4f
1154                                         && layering->m.bitrateRatios[2] == .6f))) {
1155                     msg->setString(KEY_TEMPORAL_LAYERING, AStringPrintf(
1156                             "webrtc.vp8.%u-layer", layering->m.layerCount));
1157                 } else if (layering->m.bLayerCount) {
1158                     msg->setString(KEY_TEMPORAL_LAYERING, AStringPrintf(
1159                             "android.generic.%u+%u",
1160                             layering->m.layerCount - layering->m.bLayerCount,
1161                             layering->m.bLayerCount));
1162                 } else if (layering->m.bLayerCount) {
1163                     msg->setString(KEY_TEMPORAL_LAYERING, AStringPrintf(
1164                             "android.generic.%u", layering->m.layerCount));
1165                 }
1166             }
1167             msg->removeEntryAt(msg->findEntryByName(C2_PARAMKEY_TEMPORAL_LAYERING));
1168         }
1169     }
1170 
1171     { // convert color info
1172         C2Color::primaries_t primaries;
1173         C2Color::matrix_t matrix;
1174         if (msg->findInt32("color-primaries", (int32_t*)&primaries)
1175                 && msg->findInt32("color-matrix", (int32_t*)&matrix)) {
1176             int32_t standard;
1177 
1178             if (C2Mapper::map(primaries, matrix, &standard)) {
1179                 msg->setInt32(KEY_COLOR_STANDARD, standard);
1180             }
1181 
1182             msg->removeEntryAt(msg->findEntryByName("color-primaries"));
1183             msg->removeEntryAt(msg->findEntryByName("color-matrix"));
1184         }
1185 
1186 
1187         // calculate dataspace for raw graphic buffers if not specified by component, or if
1188         // using surface with unspecified aspects (as those must be defaulted which may change
1189         // the dataspace)
1190         if ((portDomain & IS_RAW) && (mDomain & (IS_IMAGE | IS_VIDEO))) {
1191             android_dataspace dataspace;
1192             ColorAspects aspects = {
1193                 ColorAspects::RangeUnspecified, ColorAspects::PrimariesUnspecified,
1194                 ColorAspects::TransferUnspecified, ColorAspects::MatrixUnspecified
1195             };
1196             ColorUtils::getColorAspectsFromFormat(msg, aspects);
1197             ColorAspects origAspects = aspects;
1198             if (mUsingSurface) {
1199                 // get image size (default to HD)
1200                 int32_t width = 1280;
1201                 int32_t height = 720;
1202                 int32_t left, top, right, bottom;
1203                 if (msg->findRect("crop", &left, &top, &right, &bottom)) {
1204                     width = right - left + 1;
1205                     height = bottom - top + 1;
1206                 } else {
1207                     (void)msg->findInt32(KEY_WIDTH, &width);
1208                     (void)msg->findInt32(KEY_HEIGHT, &height);
1209                 }
1210                 ColorUtils::setDefaultCodecColorAspectsIfNeeded(aspects, width, height);
1211                 ColorUtils::setColorAspectsIntoFormat(aspects, msg);
1212             }
1213 
1214             if (!msg->findInt32("android._dataspace", (int32_t*)&dataspace)
1215                     || aspects.mRange != origAspects.mRange
1216                     || aspects.mPrimaries != origAspects.mPrimaries
1217                     || aspects.mTransfer != origAspects.mTransfer
1218                     || aspects.mMatrixCoeffs != origAspects.mMatrixCoeffs) {
1219                 dataspace = ColorUtils::getDataSpaceForColorAspects(aspects, true /* mayExpand */);
1220                 msg->setInt32("android._dataspace", dataspace);
1221             }
1222         }
1223 
1224         // HDR static info
1225 
1226         C2HdrStaticMetadataStruct hdr;
1227         if (msg->findFloat("smpte2086.red.x", &hdr.mastering.red.x)
1228                 && msg->findFloat("smpte2086.red.y", &hdr.mastering.red.y)
1229                 && msg->findFloat("smpte2086.green.x", &hdr.mastering.green.x)
1230                 && msg->findFloat("smpte2086.green.y", &hdr.mastering.green.y)
1231                 && msg->findFloat("smpte2086.blue.x", &hdr.mastering.blue.x)
1232                 && msg->findFloat("smpte2086.blue.y", &hdr.mastering.blue.y)
1233                 && msg->findFloat("smpte2086.white.x", &hdr.mastering.white.x)
1234                 && msg->findFloat("smpte2086.white.y", &hdr.mastering.white.y)
1235                 && msg->findFloat("smpte2086.max-luminance", &hdr.mastering.maxLuminance)
1236                 && msg->findFloat("smpte2086.min-luminance", &hdr.mastering.minLuminance)
1237                 && msg->findFloat("cta861.max-cll", &hdr.maxCll)
1238                 && msg->findFloat("cta861.max-fall", &hdr.maxFall)) {
1239             if (hdr.mastering.red.x >= 0                && hdr.mastering.red.x <= 1
1240                     && hdr.mastering.red.y >= 0         && hdr.mastering.red.y <= 1
1241                     && hdr.mastering.green.x >= 0       && hdr.mastering.green.x <= 1
1242                     && hdr.mastering.green.y >= 0       && hdr.mastering.green.y <= 1
1243                     && hdr.mastering.blue.x >= 0        && hdr.mastering.blue.x <= 1
1244                     && hdr.mastering.blue.y >= 0        && hdr.mastering.blue.y <= 1
1245                     && hdr.mastering.white.x >= 0       && hdr.mastering.white.x <= 1
1246                     && hdr.mastering.white.y >= 0       && hdr.mastering.white.y <= 1
1247                     && hdr.mastering.maxLuminance >= 0  && hdr.mastering.maxLuminance <= 65535
1248                     && hdr.mastering.minLuminance >= 0  && hdr.mastering.minLuminance <= 6.5535
1249                     && hdr.maxCll >= 0                  && hdr.maxCll <= 65535
1250                     && hdr.maxFall >= 0                 && hdr.maxFall <= 65535) {
1251                 HDRStaticInfo meta;
1252                 meta.mID = meta.kType1;
1253                 meta.sType1.mR.x = hdr.mastering.red.x / 0.00002 + 0.5;
1254                 meta.sType1.mR.y = hdr.mastering.red.y / 0.00002 + 0.5;
1255                 meta.sType1.mG.x = hdr.mastering.green.x / 0.00002 + 0.5;
1256                 meta.sType1.mG.y = hdr.mastering.green.y / 0.00002 + 0.5;
1257                 meta.sType1.mB.x = hdr.mastering.blue.x / 0.00002 + 0.5;
1258                 meta.sType1.mB.y = hdr.mastering.blue.y / 0.00002 + 0.5;
1259                 meta.sType1.mW.x = hdr.mastering.white.x / 0.00002 + 0.5;
1260                 meta.sType1.mW.y = hdr.mastering.white.y / 0.00002 + 0.5;
1261                 meta.sType1.mMaxDisplayLuminance = hdr.mastering.maxLuminance + 0.5;
1262                 meta.sType1.mMinDisplayLuminance = hdr.mastering.minLuminance / 0.0001 + 0.5;
1263                 meta.sType1.mMaxContentLightLevel = hdr.maxCll + 0.5;
1264                 meta.sType1.mMaxFrameAverageLightLevel = hdr.maxFall + 0.5;
1265                 msg->removeEntryAt(msg->findEntryByName("smpte2086.red.x"));
1266                 msg->removeEntryAt(msg->findEntryByName("smpte2086.red.y"));
1267                 msg->removeEntryAt(msg->findEntryByName("smpte2086.green.x"));
1268                 msg->removeEntryAt(msg->findEntryByName("smpte2086.green.y"));
1269                 msg->removeEntryAt(msg->findEntryByName("smpte2086.blue.x"));
1270                 msg->removeEntryAt(msg->findEntryByName("smpte2086.blue.y"));
1271                 msg->removeEntryAt(msg->findEntryByName("smpte2086.white.x"));
1272                 msg->removeEntryAt(msg->findEntryByName("smpte2086.white.y"));
1273                 msg->removeEntryAt(msg->findEntryByName("smpte2086.max-luminance"));
1274                 msg->removeEntryAt(msg->findEntryByName("smpte2086.min-luminance"));
1275                 msg->removeEntryAt(msg->findEntryByName("cta861.max-cll"));
1276                 msg->removeEntryAt(msg->findEntryByName("cta861.max-fall"));
1277                 msg->setBuffer(KEY_HDR_STATIC_INFO, ABuffer::CreateAsCopy(&meta, sizeof(meta)));
1278             } else {
1279                 ALOGD("found invalid HDR static metadata %s", msg->debugString(8).c_str());
1280             }
1281         }
1282     }
1283 
1284     ALOGV("converted to SDK values as %s", msg->debugString().c_str());
1285     return msg;
1286 }
1287 
1288 /// converts an AMessage value to a ParamUpdater value
convert(const AMessage::ItemData & from,ReflectedParamUpdater::Value * to)1289 static void convert(const AMessage::ItemData &from, ReflectedParamUpdater::Value *to) {
1290     int32_t int32Value;
1291     int64_t int64Value;
1292     sp<ABuffer> bufValue;
1293     AString strValue;
1294     float floatValue;
1295     double doubleValue;
1296 
1297     if (from.find(&int32Value)) {
1298         to->set(int32Value);
1299     } else if (from.find(&int64Value)) {
1300         to->set(int64Value);
1301     } else if (from.find(&bufValue)) {
1302         to->set(bufValue);
1303     } else if (from.find(&strValue)) {
1304         to->set(strValue);
1305     } else if (from.find(&floatValue)) {
1306         to->set(C2Value(floatValue));
1307     } else if (from.find(&doubleValue)) {
1308         // convert double to float
1309         to->set(C2Value((float)doubleValue));
1310     }
1311     // ignore all other AMessage types
1312 }
1313 
1314 /// relaxes Codec 2.0 specific value types to SDK types (mainly removes signedness and counterness
1315 /// from 32/64-bit values.)
relaxValues(ReflectedParamUpdater::Value & item)1316 static void relaxValues(ReflectedParamUpdater::Value &item) {
1317     C2Value c2Value;
1318     int32_t int32Value;
1319     int64_t int64Value;
1320     (void)item.find(&c2Value);
1321     if (c2Value.get(&int32Value) || c2Value.get((uint32_t*)&int32Value)
1322             || c2Value.get((c2_cntr32_t*)&int32Value)) {
1323         item.set(int32Value);
1324     } else if (c2Value.get(&int64Value)
1325             || c2Value.get((uint64_t*)&int64Value)
1326             || c2Value.get((c2_cntr64_t*)&int64Value)) {
1327         item.set(int64Value);
1328     }
1329 }
1330 
getReflectedFormat(const sp<AMessage> & params_,Domain configDomain) const1331 ReflectedParamUpdater::Dict CCodecConfig::getReflectedFormat(
1332         const sp<AMessage> &params_, Domain configDomain) const {
1333     // create a modifiable copy of params
1334     sp<AMessage> params = params_->dup();
1335     ALOGV("filtering with config domain %x", configDomain);
1336 
1337     // convert some macro parameters to Codec 2.0 specific expressions
1338 
1339     { // make i-frame-interval frame based
1340         float iFrameInterval;
1341         if (params->findAsFloat(KEY_I_FRAME_INTERVAL, &iFrameInterval)) {
1342             float frameRate;
1343             if (params->findAsFloat(KEY_FRAME_RATE, &frameRate)) {
1344                 params->setInt32("i-frame-period",
1345                         (frameRate <= 0 || iFrameInterval < 0)
1346                                  ? -1 /* no sync frames */
1347                                  : (int32_t)c2_min(iFrameInterval * frameRate + 0.5,
1348                                                    (float)INT32_MAX));
1349             }
1350         }
1351     }
1352 
1353     if (mDomain == (IS_VIDEO | IS_ENCODER)) {
1354         // convert capture-rate into input-time-stretch
1355         float frameRate, captureRate;
1356         if (params->findAsFloat(KEY_FRAME_RATE, &frameRate)) {
1357             if (!params->findAsFloat("time-lapse-fps", &captureRate)
1358                     && !params->findAsFloat(KEY_CAPTURE_RATE, &captureRate)) {
1359                 captureRate = frameRate;
1360             }
1361             if (captureRate > 0 && frameRate > 0) {
1362                 params->setFloat(C2_PARAMKEY_INPUT_TIME_STRETCH, captureRate / frameRate);
1363             }
1364         }
1365     }
1366 
1367     {   // reflect temporal layering into a binary blob
1368         AString schema;
1369         if (params->findString(KEY_TEMPORAL_LAYERING, &schema)) {
1370             unsigned int numLayers = 0;
1371             unsigned int numBLayers = 0;
1372             int tags;
1373             char dummy;
1374             std::unique_ptr<C2StreamTemporalLayeringTuning::output> layering;
1375             if (sscanf(schema.c_str(), "webrtc.vp8.%u-layer%c", &numLayers, &dummy) == 1
1376                 && numLayers > 0) {
1377                 switch (numLayers) {
1378                     case 1:
1379                         layering = C2StreamTemporalLayeringTuning::output::AllocUnique(
1380                                 {}, 0u, 1u, 0u);
1381                         break;
1382                     case 2:
1383                         layering = C2StreamTemporalLayeringTuning::output::AllocUnique(
1384                                 { .6f }, 0u, 2u, 0u);
1385                         break;
1386                     case 3:
1387                         layering = C2StreamTemporalLayeringTuning::output::AllocUnique(
1388                                 { .4f, .6f }, 0u, 3u, 0u);
1389                         break;
1390                     default:
1391                         layering = C2StreamTemporalLayeringTuning::output::AllocUnique(
1392                                 { .25f, .4f, .6f }, 0u, 4u, 0u);
1393                         break;
1394                 }
1395             } else if ((tags = sscanf(schema.c_str(), "android.generic.%u%c%u%c",
1396                         &numLayers, &dummy, &numBLayers, &dummy))
1397                 && (tags == 1 || (tags == 3 && dummy == '+'))
1398                 && numLayers > 0 && numLayers < UINT32_MAX - numBLayers) {
1399                 layering = C2StreamTemporalLayeringTuning::output::AllocUnique(
1400                         {}, 0u, numLayers + numBLayers, numBLayers);
1401             } else {
1402                 ALOGD("Ignoring unsupported ts-schema [%s]", schema.c_str());
1403             }
1404             if (layering) {
1405                 params->setBuffer(C2_PARAMKEY_TEMPORAL_LAYERING,
1406                                   ABuffer::CreateAsCopy(layering.get(), layering->size()));
1407             }
1408         }
1409     }
1410 
1411     { // convert from MediaFormat rect to Codec 2.0 rect
1412         int32_t offset;
1413         int32_t end;
1414         AMessage::ItemData item;
1415         if (params->findInt32("crop-left", &offset) && params->findInt32("crop-right", &end)
1416                 && offset >= 0 && end >= offset - 1) {
1417             size_t ix = params->findEntryByName("crop-right");
1418             params->setEntryNameAt(ix, "crop-width");
1419             item.set(end - offset + 1);
1420             params->setEntryAt(ix, item);
1421         }
1422         if (params->findInt32("crop-top", &offset) && params->findInt32("crop-bottom", &end)
1423                 && offset >= 0 && end >= offset - 1) {
1424             size_t ix = params->findEntryByName("crop-bottom");
1425             params->setEntryNameAt(ix, "crop-height");
1426             item.set(end - offset + 1);
1427             params->setEntryAt(ix, item);
1428         }
1429     }
1430 
1431     { // convert color info
1432         int32_t standard;
1433         if (params->findInt32(KEY_COLOR_STANDARD, &standard)) {
1434             C2Color::primaries_t primaries;
1435             C2Color::matrix_t matrix;
1436 
1437             if (C2Mapper::map(standard, &primaries, &matrix)) {
1438                 params->setInt32("color-primaries", primaries);
1439                 params->setInt32("color-matrix", matrix);
1440             }
1441         }
1442 
1443         sp<ABuffer> hdrMeta;
1444         if (params->findBuffer(KEY_HDR_STATIC_INFO, &hdrMeta)
1445                 && hdrMeta->size() == sizeof(HDRStaticInfo)) {
1446             HDRStaticInfo *meta = (HDRStaticInfo*)hdrMeta->data();
1447             if (meta->mID == meta->kType1) {
1448                 params->setFloat("smpte2086.red.x", meta->sType1.mR.x * 0.00002);
1449                 params->setFloat("smpte2086.red.y", meta->sType1.mR.y * 0.00002);
1450                 params->setFloat("smpte2086.green.x", meta->sType1.mG.x * 0.00002);
1451                 params->setFloat("smpte2086.green.y", meta->sType1.mG.y * 0.00002);
1452                 params->setFloat("smpte2086.blue.x", meta->sType1.mB.x * 0.00002);
1453                 params->setFloat("smpte2086.blue.y", meta->sType1.mB.y * 0.00002);
1454                 params->setFloat("smpte2086.white.x", meta->sType1.mW.x * 0.00002);
1455                 params->setFloat("smpte2086.white.y", meta->sType1.mW.y * 0.00002);
1456                 params->setFloat("smpte2086.max-luminance", meta->sType1.mMaxDisplayLuminance);
1457                 params->setFloat("smpte2086.min-luminance", meta->sType1.mMinDisplayLuminance * 0.0001);
1458                 params->setFloat("cta861.max-cll", meta->sType1.mMaxContentLightLevel);
1459                 params->setFloat("cta861.max-fall", meta->sType1.mMaxFrameAverageLightLevel);
1460             }
1461         }
1462     }
1463 
1464     // this is to verify that we set proper signedness for standard parameters
1465     bool beVeryStrict = property_get_bool("debug.stagefright.ccodec_strict_type", false);
1466     // this is to allow vendors to use the wrong signedness for standard parameters
1467     bool beVeryLax = property_get_bool("debug.stagefright.ccodec_lax_type", false);
1468 
1469     ReflectedParamUpdater::Dict filtered;
1470     for (size_t ix = 0; ix < params->countEntries(); ++ix) {
1471         AMessage::Type type;
1472         AString name = params->getEntryNameAt(ix, &type);
1473         AMessage::ItemData msgItem = params->getEntryAt(ix);
1474         ReflectedParamUpdater::Value item;
1475         convert(msgItem, &item); // convert item to param updater item
1476 
1477         if (name.startsWith("vendor.")) {
1478             // vendor params pass through as is
1479             filtered.emplace(name.c_str(), item);
1480             continue;
1481         }
1482         // standard parameters may get modified, filtered or duplicated
1483         for (const ConfigMapper &cm : mStandardParams->getConfigMappersForSdkKey(name.c_str())) {
1484             // note: we ignore port domain for configuration
1485             if ((cm.domain() & configDomain)
1486                     // component domain + kind (these must match)
1487                     && (cm.domain() & mDomain) == mDomain) {
1488                 // map arithmetic values, pass through string or buffer
1489                 switch (type) {
1490                     case AMessage::kTypeBuffer:
1491                     case AMessage::kTypeString:
1492                         break;
1493                     case AMessage::kTypeInt32:
1494                     case AMessage::kTypeInt64:
1495                     case AMessage::kTypeFloat:
1496                     case AMessage::kTypeDouble:
1497                         // for now only map settings with mappers as we are not creating
1498                         // signed <=> unsigned mappers
1499                         // TODO: be precise about signed unsigned
1500                         if (beVeryStrict || cm.mapper()) {
1501                             item.set(cm.mapFromMessage(params->getEntryAt(ix)));
1502                             // also allow to relax type strictness
1503                             if (beVeryLax) {
1504                                 relaxValues(item);
1505                             }
1506                         }
1507                         break;
1508                     default:
1509                         continue;
1510                 }
1511                 filtered.emplace(cm.path(), item);
1512             }
1513         }
1514     }
1515     ALOGV("filtered %s to %s", params->debugString(4).c_str(),
1516             filtered.debugString(4).c_str());
1517     return filtered;
1518 }
1519 
getConfigUpdateFromSdkParams(std::shared_ptr<Codec2Client::Component> component,const sp<AMessage> & sdkParams,Domain configDomain,c2_blocking_t blocking,std::vector<std::unique_ptr<C2Param>> * configUpdate) const1520 status_t CCodecConfig::getConfigUpdateFromSdkParams(
1521         std::shared_ptr<Codec2Client::Component> component,
1522         const sp<AMessage> &sdkParams, Domain configDomain,
1523         c2_blocking_t blocking,
1524         std::vector<std::unique_ptr<C2Param>> *configUpdate) const {
1525     ReflectedParamUpdater::Dict params = getReflectedFormat(sdkParams, configDomain);
1526 
1527     std::vector<C2Param::Index> indices;
1528     mParamUpdater->getParamIndicesFromMessage(params, &indices);
1529     if (indices.empty()) {
1530         ALOGD("no recognized params in: %s", params.debugString().c_str());
1531         return OK;
1532     }
1533 
1534     configUpdate->clear();
1535     std::vector<C2Param::Index> supportedIndices;
1536     for (C2Param::Index ix : indices) {
1537         if (mSupportedIndices.count(ix)) {
1538             supportedIndices.push_back(ix);
1539         } else if (mLocalParams.count(ix)) {
1540             // query local parameter here
1541             auto it = mCurrentConfig.find(ix);
1542             if (it != mCurrentConfig.end()) {
1543                 configUpdate->emplace_back(C2Param::Copy(*it->second));
1544             }
1545         }
1546     }
1547 
1548     c2_status_t err = component->query({ }, supportedIndices, blocking, configUpdate);
1549     if (err != C2_OK) {
1550         ALOGD("query failed after returning %zu params => %s", configUpdate->size(), asString(err));
1551     }
1552 
1553     if (configUpdate->size()) {
1554         mParamUpdater->updateParamsFromMessage(params, configUpdate);
1555     }
1556     return OK;
1557 }
1558 
setParameters(std::shared_ptr<Codec2Client::Component> component,std::vector<std::unique_ptr<C2Param>> & configUpdate,c2_blocking_t blocking)1559 status_t CCodecConfig::setParameters(
1560         std::shared_ptr<Codec2Client::Component> component,
1561         std::vector<std::unique_ptr<C2Param>> &configUpdate,
1562         c2_blocking_t blocking) {
1563     status_t result = OK;
1564     if (configUpdate.empty()) {
1565         return OK;
1566     }
1567 
1568     std::vector<C2Param::Index> indices;
1569     std::vector<C2Param *> paramVector;
1570     for (const std::unique_ptr<C2Param> &param : configUpdate) {
1571         if (mSupportedIndices.count(param->index())) {
1572             // component parameter
1573             paramVector.push_back(param.get());
1574             indices.push_back(param->index());
1575         } else if (mLocalParams.count(param->index())) {
1576             // handle local parameter here
1577             LocalParamValidator validator = mLocalParams.find(param->index())->second;
1578             c2_status_t err = C2_OK;
1579             std::unique_ptr<C2Param> copy = C2Param::Copy(*param);
1580             if (validator) {
1581                 err = validator(copy);
1582             }
1583             if (err == C2_OK) {
1584                 ALOGV("updated local parameter value for %s",
1585                         mParamUpdater->getParamName(param->index()).c_str());
1586 
1587                 mCurrentConfig[param->index()] = std::move(copy);
1588             } else {
1589                 ALOGD("failed to set parameter value for %s => %s",
1590                         mParamUpdater->getParamName(param->index()).c_str(), asString(err));
1591                 result = BAD_VALUE;
1592             }
1593         }
1594     }
1595     // update subscribed param indices
1596     subscribeToConfigUpdate(component, indices, blocking);
1597 
1598     std::vector<std::unique_ptr<C2SettingResult>> failures;
1599     c2_status_t err = component->config(paramVector, blocking, &failures);
1600     if (err != C2_OK) {
1601         ALOGD("config failed => %s", asString(err));
1602         // This is non-fatal.
1603     }
1604     for (const std::unique_ptr<C2SettingResult> &failure : failures) {
1605         switch (failure->failure) {
1606             case C2SettingResult::BAD_VALUE:
1607                 ALOGD("Bad parameter value");
1608                 result = BAD_VALUE;
1609                 break;
1610             default:
1611                 ALOGV("failure = %d", int(failure->failure));
1612                 break;
1613         }
1614     }
1615 
1616     // Re-query parameter values in case config could not update them and update the current
1617     // configuration.
1618     configUpdate.clear();
1619     err = component->query({}, indices, blocking, &configUpdate);
1620     if (err != C2_OK) {
1621         ALOGD("query failed after returning %zu params => %s", configUpdate.size(), asString(err));
1622     }
1623     (void)updateConfiguration(configUpdate, ALL);
1624 
1625     // TODO: error value
1626     return result;
1627 }
1628 
getConfigParameterValue(C2Param::Index index) const1629 const C2Param *CCodecConfig::getConfigParameterValue(C2Param::Index index) const {
1630     auto it = mCurrentConfig.find(index);
1631     if (it == mCurrentConfig.end()) {
1632         return nullptr;
1633     } else {
1634         return it->second.get();
1635     }
1636 }
1637 
1638 }  // namespace android
1639