1 /*
2  * Copyright 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef CODEC2_COMMON_PARAM_TYPES_H
18 #define CODEC2_COMMON_PARAM_TYPES_H
19 
20 #ifndef LOG_TAG
21 #define LOG_TAG "Codec2-ParamTypes"
22 #endif
23 #include <android-base/logging.h>
24 
25 #include <log/log_safetynet.h>
26 #include <media/stagefright/foundation/AUtils.h>
27 
28 #include <C2Component.h>
29 #include <C2Param.h>
30 #include <C2ParamInternal.h>
31 #include <util/C2ParamUtils.h>
32 
33 #include <algorithm>
34 #include <unordered_map>
35 
36 namespace android {
37 
38 template <typename EnumClass>
underlying_value(EnumClass x)39 typename std::underlying_type<EnumClass>::type underlying_value(EnumClass x) {
40     return static_cast<typename std::underlying_type<EnumClass>::type>(x);
41 }
42 
43 template <typename Common, typename DstVector, typename SrcVector>
copyVector(DstVector * d,const SrcVector & s)44 void copyVector(DstVector* d, const SrcVector& s) {
45     static_assert(sizeof(Common) == sizeof(decltype((*d)[0])),
46             "DstVector's component size does not match Common");
47     static_assert(sizeof(Common) == sizeof(decltype(s[0])),
48             "SrcVector's component size does not match Common");
49     d->resize(s.size());
50     std::copy(
51             reinterpret_cast<const Common*>(&s[0]),
52             reinterpret_cast<const Common*>(&s[0] + s.size()),
53             reinterpret_cast<Common*>(&(*d)[0]));
54 }
55 
56 // {offset, size} -> FieldId
57 template <typename FieldId>
SetFieldId(FieldId * d,uint32_t offset,uint32_t size)58 void SetFieldId(FieldId *d, uint32_t offset, uint32_t size) {
59     d->offset = offset;
60     d->size = size;
61 }
62 
63 // FieldId -> offset
64 template <typename FieldId>
GetOffsetFromFieldId(const FieldId & s)65 uint32_t GetOffsetFromFieldId(const FieldId &s) {
66     return s.offset;
67 }
68 
69 // FieldId -> size
70 template <typename FieldId>
GetSizeFromFieldId(const FieldId & s)71 uint32_t GetSizeFromFieldId(const FieldId &s) {
72     return s.size;
73 }
74 
75 // C2ParamField -> ParamField
76 template <typename ParamField>
objcpy(ParamField * d,const C2ParamField & s)77 bool objcpy(ParamField *d, const C2ParamField &s) {
78     d->index = static_cast<decltype(d->index)>(_C2ParamInspector::GetIndex(s));
79     SetFieldId(
80             &d->fieldId,
81             static_cast<uint32_t>(_C2ParamInspector::GetOffset(s)),
82             static_cast<uint32_t>(_C2ParamInspector::GetSize(s)));
83     return true;
84 }
85 
86 template <typename ParamField>
87 struct C2ParamFieldBuilder : public C2ParamField {
C2ParamFieldBuilderC2ParamFieldBuilder88     C2ParamFieldBuilder() : C2ParamField(
89             static_cast<C2Param::Index>(static_cast<uint32_t>(0)), 0, 0) {
90     }
91     // ParamField -> C2ParamField
C2ParamFieldBuilderC2ParamFieldBuilder92     C2ParamFieldBuilder(const ParamField& s) : C2ParamField(
93             static_cast<C2Param::Index>(static_cast<uint32_t>(s.index)),
94             static_cast<uint32_t>(GetOffsetFromFieldId(s.fieldId)),
95             static_cast<uint32_t>(GetSizeFromFieldId(s.fieldId))) {
96     }
97 };
98 
99 // C2WorkOrdinalStruct -> WorkOrdinal
100 template <typename WorkOrdinal>
objcpy(WorkOrdinal * d,const C2WorkOrdinalStruct & s)101 bool objcpy(WorkOrdinal *d, const C2WorkOrdinalStruct &s) {
102     d->frameIndex = static_cast<uint64_t>(s.frameIndex.peeku());
103     d->timestampUs = static_cast<uint64_t>(s.timestamp.peeku());
104     d->customOrdinal = static_cast<uint64_t>(s.customOrdinal.peeku());
105     return true;
106 }
107 
108 // WorkOrdinal -> C2WorkOrdinalStruct
109 template <typename WorkOrdinal>
objcpy(C2WorkOrdinalStruct * d,const WorkOrdinal & s)110 bool objcpy(C2WorkOrdinalStruct *d, const WorkOrdinal &s) {
111     d->frameIndex = c2_cntr64_t(s.frameIndex);
112     d->timestamp = c2_cntr64_t(s.timestampUs);
113     d->customOrdinal = c2_cntr64_t(s.customOrdinal);
114     return true;
115 }
116 
117 // C2FieldSupportedValues::range's type -> ValueRange
118 template <typename ValueRange>
objcpy(ValueRange * d,const decltype (C2FieldSupportedValues::range)& s)119 bool objcpy(
120         ValueRange* d,
121         const decltype(C2FieldSupportedValues::range)& s) {
122     d->min    = static_cast<decltype(d->min)>(s.min.u64);
123     d->max    = static_cast<decltype(d->max)>(s.max.u64);
124     d->step   = static_cast<decltype(d->step)>(s.step.u64);
125     d->num    = static_cast<decltype(d->num)>(s.num.u64);
126     d->denom  = static_cast<decltype(d->denom)>(s.denom.u64);
127     return true;
128 }
129 
130 // ValueRange -> C2FieldSupportedValues::range's type
131 template <typename ValueRange>
objcpy(decltype (C2FieldSupportedValues::range)* d,const ValueRange & s)132 bool objcpy(
133         decltype(C2FieldSupportedValues::range)* d,
134         const ValueRange& s) {
135     d->min.u64  = static_cast<uint64_t>(s.min);
136     d->max.u64  = static_cast<uint64_t>(s.max);
137     d->step.u64 = static_cast<uint64_t>(s.step);
138     d->num.u64  = static_cast<uint64_t>(s.num);
139     d->denom.u64  = static_cast<uint64_t>(s.denom);
140     return true;
141 }
142 
143 template <typename Status>
SetStatus(Status * dst,c2_status_t src)144 void SetStatus(Status *dst, c2_status_t src) {
145     *dst = static_cast<Status>(src);
146 }
147 
148 template <typename Status>
GetStatus(const Status & status)149 c2_status_t GetStatus(const Status &status) {
150     return static_cast<c2_status_t>(status);
151 }
152 
153 // C2FieldSupportedValues -> FieldSupportedValues
154 template <typename FieldSupportedValues>
155 bool objcpy(FieldSupportedValues *d, const C2FieldSupportedValues &s);
156 
157 // FieldSupportedValues -> C2FieldSupportedValues
158 template <typename FieldSupportedValues>
159 bool objcpy(C2FieldSupportedValues *d, const FieldSupportedValues &s);
160 
161 // C2FieldSupportedValuesQuery -> FieldSupportedValuesQuery, FieldSupportedValuesQueryResult
162 template <typename FieldSupportedValuesQueryPtr>
objcpy(FieldSupportedValuesQueryPtr dq,nullptr_t,const C2FieldSupportedValuesQuery & s)163 bool objcpy(
164         FieldSupportedValuesQueryPtr dq,
165         nullptr_t,
166         const C2FieldSupportedValuesQuery& s) {
167     static_assert(!std::is_null_pointer_v<FieldSupportedValuesQueryPtr>);
168     static_assert(std::is_pointer_v<FieldSupportedValuesQueryPtr>);
169     typedef std::remove_pointer_t<FieldSupportedValuesQueryPtr> FieldSupportedValuesQuery;
170     if (!dq) {
171         return false;
172     }
173     if (!objcpy(&dq->field, s.field())) {
174         LOG(ERROR) << "Invalid C2FieldSupportedValuesQuery::field.";
175         return false;
176     }
177     switch (s.type()) {
178     case C2FieldSupportedValuesQuery::POSSIBLE:
179         dq->type = FieldSupportedValuesQuery::Type::POSSIBLE;
180         break;
181     case C2FieldSupportedValuesQuery::CURRENT:
182         dq->type = FieldSupportedValuesQuery::Type::CURRENT;
183         break;
184     default:
185         LOG(DEBUG) << "Unrecognized C2FieldSupportedValuesQuery::type_t "
186                    << "with underlying value " << underlying_value(s.type())
187                    << ".";
188         dq->type = static_cast<decltype(dq->type)>(s.type());
189     }
190     return true;
191 }
192 
193 template <typename FieldSupportedValuesQueryResultPtr>
objcpy(nullptr_t,FieldSupportedValuesQueryResultPtr dr,const C2FieldSupportedValuesQuery & s)194 bool objcpy(
195         nullptr_t,
196         FieldSupportedValuesQueryResultPtr dr,
197         const C2FieldSupportedValuesQuery& s) {
198     static_assert(!std::is_null_pointer_v<FieldSupportedValuesQueryResultPtr>);
199     static_assert(std::is_pointer_v<FieldSupportedValuesQueryResultPtr>);
200     if (!dr) {
201         return false;
202     }
203     SetStatus(&dr->status, s.status);
204     return objcpy(&dr->values, s.values);
205 }
206 
207 template <typename FieldSupportedValuesQueryPtr, typename FieldSupportedValuesQueryResultPtr>
objcpy(FieldSupportedValuesQueryPtr dq,FieldSupportedValuesQueryResultPtr dr,const C2FieldSupportedValuesQuery & s)208 bool objcpy(
209         FieldSupportedValuesQueryPtr dq,
210         FieldSupportedValuesQueryResultPtr dr,
211         const C2FieldSupportedValuesQuery& s) {
212     if (!objcpy(dq, nullptr, s)) {
213         return false;
214     }
215     return objcpy(nullptr, dr, s);
216 }
217 
218 // FieldSupportedValuesQuery -> C2FieldSupportedValuesQuery
219 template <typename FieldSupportedValuesQuery>
objcpy(C2FieldSupportedValuesQuery * d,const FieldSupportedValuesQuery & s)220 bool objcpy(
221         C2FieldSupportedValuesQuery* d,
222         const FieldSupportedValuesQuery& s) {
223     C2FieldSupportedValuesQuery::type_t dType;
224     switch (s.type) {
225     case FieldSupportedValuesQuery::Type::POSSIBLE:
226         dType = C2FieldSupportedValuesQuery::POSSIBLE;
227         break;
228     case FieldSupportedValuesQuery::Type::CURRENT:
229         dType = C2FieldSupportedValuesQuery::CURRENT;
230         break;
231     default:
232         LOG(DEBUG) << "Unrecognized FieldSupportedValuesQuery::Type "
233                    << "with underlying value " << underlying_value(s.type)
234                    << ".";
235         dType = static_cast<C2FieldSupportedValuesQuery::type_t>(s.type);
236     }
237     *d = C2FieldSupportedValuesQuery(C2ParamFieldBuilder(s.field), dType);
238     return true;
239 }
240 
241 // FieldSupportedValuesQuery, FieldSupportedValuesQueryResult ->
242 // C2FieldSupportedValuesQuery
243 template <typename FieldSupportedValuesQuery,
244           typename FieldSupportedValuesQueryResult>
objcpy(C2FieldSupportedValuesQuery * d,const FieldSupportedValuesQuery & sq,const FieldSupportedValuesQueryResult & sr)245 bool objcpy(
246         C2FieldSupportedValuesQuery* d,
247         const FieldSupportedValuesQuery& sq,
248         const FieldSupportedValuesQueryResult& sr) {
249     if (!objcpy(d, sq)) {
250         LOG(ERROR) << "Invalid FieldSupportedValuesQuery.";
251         return false;
252     }
253     d->status = GetStatus(sr.status);
254     if (!objcpy(&d->values, sr.values)) {
255         LOG(ERROR) << "Invalid FieldSupportedValuesQueryResult::values.";
256         return false;
257     }
258     return true;
259 }
260 
261 // C2Component::Traits -> IComponentStore::ComponentTraits
262 template <typename ComponentTraits>
objcpy(ComponentTraits * d,const C2Component::Traits & s)263 bool objcpy(
264         ComponentTraits *d,
265         const C2Component::Traits &s) {
266     d->name = s.name;
267 
268     switch (s.domain) {
269     case C2Component::DOMAIN_VIDEO:
270         d->domain = ComponentTraits::Domain::VIDEO;
271         break;
272     case C2Component::DOMAIN_AUDIO:
273         d->domain = ComponentTraits::Domain::AUDIO;
274         break;
275     case C2Component::DOMAIN_IMAGE:
276         d->domain = ComponentTraits::Domain::IMAGE;
277         break;
278     case C2Component::DOMAIN_OTHER:
279         d->domain = ComponentTraits::Domain::OTHER;
280         break;
281     default:
282         LOG(DEBUG) << "Unrecognized C2Component::domain_t "
283                    << "with underlying value " << underlying_value(s.domain)
284                    << ".";
285         d->domain = static_cast<decltype(d->domain)>(s.domain);
286     }
287 
288     switch (s.kind) {
289     case C2Component::KIND_DECODER:
290         d->kind = ComponentTraits::Kind::DECODER;
291         break;
292     case C2Component::KIND_ENCODER:
293         d->kind = ComponentTraits::Kind::ENCODER;
294         break;
295     case C2Component::KIND_OTHER:
296         d->kind = ComponentTraits::Kind::OTHER;
297         break;
298     default:
299         LOG(DEBUG) << "Unrecognized C2Component::kind_t "
300                    << "with underlying value " << underlying_value(s.kind)
301                    << ".";
302         d->kind = static_cast<decltype(d->kind)>(s.kind);
303     }
304 
305     d->rank = static_cast<uint32_t>(s.rank);
306 
307     d->mediaType = s.mediaType;
308 
309     d->aliases.resize(s.aliases.size());
310     for (size_t ix = s.aliases.size(); ix > 0; ) {
311         --ix;
312         d->aliases[ix] = s.aliases[ix];
313     }
314     return true;
315 }
316 
317 // ComponentTraits -> C2Component::Traits, std::unique_ptr<std::vector<std::string>>
318 template <typename ComponentTraits>
objcpy(C2Component::Traits * d,const ComponentTraits & s)319 bool objcpy(
320         C2Component::Traits* d,
321         const ComponentTraits& s) {
322     d->name = s.name.c_str();
323 
324     switch (s.domain) {
325     case ComponentTraits::Domain::VIDEO:
326         d->domain = C2Component::DOMAIN_VIDEO;
327         break;
328     case ComponentTraits::Domain::AUDIO:
329         d->domain = C2Component::DOMAIN_AUDIO;
330         break;
331     case ComponentTraits::Domain::IMAGE:
332         d->domain = C2Component::DOMAIN_IMAGE;
333         break;
334     case ComponentTraits::Domain::OTHER:
335         d->domain = C2Component::DOMAIN_OTHER;
336         break;
337     default:
338         LOG(DEBUG) << "Unrecognized ComponentTraits::Domain "
339                    << "with underlying value " << underlying_value(s.domain)
340                    << ".";
341         d->domain = static_cast<C2Component::domain_t>(s.domain);
342     }
343 
344     switch (s.kind) {
345     case ComponentTraits::Kind::DECODER:
346         d->kind = C2Component::KIND_DECODER;
347         break;
348     case ComponentTraits::Kind::ENCODER:
349         d->kind = C2Component::KIND_ENCODER;
350         break;
351     case ComponentTraits::Kind::OTHER:
352         d->kind = C2Component::KIND_OTHER;
353         break;
354     default:
355         LOG(DEBUG) << "Unrecognized ComponentTraits::Kind "
356                    << "with underlying value " << underlying_value(s.kind)
357                    << ".";
358         d->kind = static_cast<C2Component::kind_t>(s.kind);
359     }
360 
361     d->rank = static_cast<C2Component::rank_t>(s.rank);
362     d->mediaType = s.mediaType.c_str();
363     d->aliases.resize(s.aliases.size());
364     for (size_t i = 0; i < s.aliases.size(); ++i) {
365         d->aliases[i] = s.aliases[i];
366     }
367     return true;
368 }
369 
370 // C2ParamFieldValues -> ParamFieldValues
371 template <typename ParamFieldValues>
objcpy(ParamFieldValues * d,const C2ParamFieldValues & s)372 bool objcpy(
373         ParamFieldValues *d,
374         const C2ParamFieldValues &s) {
375     if (!objcpy(&d->paramOrField, s.paramOrField)) {
376         LOG(ERROR) << "Invalid C2ParamFieldValues::paramOrField.";
377         return false;
378     }
379     if (s.values) {
380         d->values.resize(1);
381         if (!objcpy(&d->values[0], *s.values)) {
382             LOG(ERROR) << "Invalid C2ParamFieldValues::values.";
383             return false;
384         }
385         return true;
386     }
387     d->values.resize(0);
388     return true;
389 }
390 
391 // ParamFieldValues -> C2ParamFieldValues
392 template <typename ParamFieldValues>
objcpy(C2ParamFieldValues * d,const ParamFieldValues & s)393 bool objcpy(
394         C2ParamFieldValues *d,
395         const ParamFieldValues &s) {
396     d->paramOrField = C2ParamFieldBuilder(s.paramOrField);
397     if (s.values.size() == 1) {
398         d->values = std::make_unique<C2FieldSupportedValues>();
399         if (!objcpy(d->values.get(), s.values[0])) {
400             LOG(ERROR) << "Invalid ParamFieldValues::values.";
401             return false;
402         }
403         return true;
404     } else if (s.values.size() == 0) {
405         d->values.reset();
406         return true;
407     }
408     LOG(ERROR) << "Invalid ParamFieldValues: "
409                   "Two or more FieldSupportedValues objects exist in "
410                   "ParamFieldValues. "
411                   "Only zero or one is allowed.";
412     return false;
413 }
414 
415 // C2SettingResult -> SettingResult
416 template <typename SettingResult>
objcpy(SettingResult * d,const C2SettingResult & s)417 bool objcpy(
418         SettingResult *d,
419         const C2SettingResult &s) {
420     switch (s.failure) {
421     case C2SettingResult::BAD_TYPE:
422         d->failure = SettingResult::Failure::BAD_TYPE;
423         break;
424     case C2SettingResult::BAD_PORT:
425         d->failure = SettingResult::Failure::BAD_PORT;
426         break;
427     case C2SettingResult::BAD_INDEX:
428         d->failure = SettingResult::Failure::BAD_INDEX;
429         break;
430     case C2SettingResult::READ_ONLY:
431         d->failure = SettingResult::Failure::READ_ONLY;
432         break;
433     case C2SettingResult::MISMATCH:
434         d->failure = SettingResult::Failure::MISMATCH;
435         break;
436     case C2SettingResult::BAD_VALUE:
437         d->failure = SettingResult::Failure::BAD_VALUE;
438         break;
439     case C2SettingResult::CONFLICT:
440         d->failure = SettingResult::Failure::CONFLICT;
441         break;
442     case C2SettingResult::UNSUPPORTED:
443         d->failure = SettingResult::Failure::UNSUPPORTED;
444         break;
445     case C2SettingResult::INFO_BAD_VALUE:
446         d->failure = SettingResult::Failure::INFO_BAD_VALUE;
447         break;
448     case C2SettingResult::INFO_CONFLICT:
449         d->failure = SettingResult::Failure::INFO_CONFLICT;
450         break;
451     default:
452         LOG(DEBUG) << "Unrecognized C2SettingResult::Failure "
453                    << "with underlying value " << underlying_value(s.failure)
454                    << ".";
455         d->failure = static_cast<decltype(d->failure)>(s.failure);
456     }
457     if (!objcpy(&d->field, s.field)) {
458         LOG(ERROR) << "Invalid C2SettingResult::field.";
459         return false;
460     }
461     d->conflicts.resize(s.conflicts.size());
462     size_t i = 0;
463     for (const C2ParamFieldValues& sConflict : s.conflicts) {
464         auto &dConflict = d->conflicts[i++];
465         if (!objcpy(&dConflict, sConflict)) {
466             LOG(ERROR) << "Invalid C2SettingResult::conflicts["
467                        << i - 1 << "].";
468             return false;
469         }
470     }
471     return true;
472 }
473 
474 // SettingResult -> std::unique_ptr<C2SettingResult>
475 template <typename SettingResult>
objcpy(std::unique_ptr<C2SettingResult> * d,const SettingResult & s)476 bool objcpy(
477         std::unique_ptr<C2SettingResult> *d,
478         const SettingResult &s) {
479     typedef decltype((*d)->field) ParamField;
480     *d = std::unique_ptr<C2SettingResult>(new C2SettingResult {
481             .field = C2ParamFieldValues(C2ParamFieldBuilder<ParamField>()) });
482     if (!*d) {
483         LOG(ERROR) << "No memory for C2SettingResult.";
484         return false;
485     }
486 
487     // failure
488     switch (s.failure) {
489     case SettingResult::Failure::BAD_TYPE:
490         (*d)->failure = C2SettingResult::BAD_TYPE;
491         break;
492     case SettingResult::Failure::BAD_PORT:
493         (*d)->failure = C2SettingResult::BAD_PORT;
494         break;
495     case SettingResult::Failure::BAD_INDEX:
496         (*d)->failure = C2SettingResult::BAD_INDEX;
497         break;
498     case SettingResult::Failure::READ_ONLY:
499         (*d)->failure = C2SettingResult::READ_ONLY;
500         break;
501     case SettingResult::Failure::MISMATCH:
502         (*d)->failure = C2SettingResult::MISMATCH;
503         break;
504     case SettingResult::Failure::BAD_VALUE:
505         (*d)->failure = C2SettingResult::BAD_VALUE;
506         break;
507     case SettingResult::Failure::CONFLICT:
508         (*d)->failure = C2SettingResult::CONFLICT;
509         break;
510     case SettingResult::Failure::UNSUPPORTED:
511         (*d)->failure = C2SettingResult::UNSUPPORTED;
512         break;
513     case SettingResult::Failure::INFO_BAD_VALUE:
514         (*d)->failure = C2SettingResult::INFO_BAD_VALUE;
515         break;
516     case SettingResult::Failure::INFO_CONFLICT:
517         (*d)->failure = C2SettingResult::INFO_CONFLICT;
518         break;
519     default:
520         LOG(DEBUG) << "Unrecognized SettingResult::Failure "
521                    << "with underlying value " << underlying_value(s.failure)
522                    << ".";
523         (*d)->failure = static_cast<C2SettingResult::Failure>(s.failure);
524     }
525 
526     // field
527     if (!objcpy(&(*d)->field, s.field)) {
528         LOG(ERROR) << "Invalid SettingResult::field.";
529         return false;
530     }
531 
532     // conflicts
533     (*d)->conflicts.clear();
534     (*d)->conflicts.reserve(s.conflicts.size());
535     for (const auto& sConflict : s.conflicts) {
536         (*d)->conflicts.emplace_back(
537                 C2ParamFieldValues{ C2ParamFieldBuilder<ParamField>(), nullptr });
538         if (!objcpy(&(*d)->conflicts.back(), sConflict)) {
539             LOG(ERROR) << "Invalid SettingResult::conflicts.";
540             return false;
541         }
542     }
543     return true;
544 }
545 
546 // C2ParamDescriptor -> ParamDescriptor
547 template <typename ParamDescriptor>
objcpy(ParamDescriptor * d,const C2ParamDescriptor & s)548 bool objcpy(ParamDescriptor *d, const C2ParamDescriptor &s) {
549     d->index = static_cast<decltype(d->index)>(s.index());
550     d->attrib = static_cast<decltype(d->attrib)>(
551             _C2ParamInspector::GetAttrib(s));
552     d->name = s.name();
553     copyVector<uint32_t>(&d->dependencies, s.dependencies());
554     return true;
555 }
556 
557 // ParamDescriptor -> C2ParamDescriptor
558 template <typename ParamDescriptor>
objcpy(std::shared_ptr<C2ParamDescriptor> * d,const ParamDescriptor & s)559 bool objcpy(std::shared_ptr<C2ParamDescriptor> *d, const ParamDescriptor &s) {
560     std::vector<C2Param::Index> dDependencies;
561     dDependencies.reserve(s.dependencies.size());
562     for (const auto& sDependency : s.dependencies) {
563         dDependencies.emplace_back(static_cast<uint32_t>(sDependency));
564     }
565     *d = std::make_shared<C2ParamDescriptor>(
566             C2Param::Index(static_cast<uint32_t>(s.index)),
567             static_cast<C2ParamDescriptor::attrib_t>(s.attrib),
568             C2String(s.name.c_str()),
569             std::move(dDependencies));
570     return true;
571 }
572 
573 // C2StructDescriptor -> StructDescriptor
574 template <typename StructDescriptor>
objcpy(StructDescriptor * d,const C2StructDescriptor & s)575 bool objcpy(StructDescriptor *d, const C2StructDescriptor &s) {
576     d->type = static_cast<decltype(d->type)>(s.coreIndex().coreIndex());
577     d->fields.resize(s.numFields());
578     size_t i = 0;
579     for (const C2FieldDescriptor& sField : s) {
580         auto& dField = d->fields[i++];
581         SetFieldId(
582                 &dField.fieldId,
583                 _C2ParamInspector::GetOffset(sField),
584                 _C2ParamInspector::GetSize(sField));
585         dField.type = static_cast<decltype(dField.type)>(sField.type());
586         dField.extent = static_cast<uint32_t>(sField.extent());
587         dField.name = static_cast<decltype(dField.name)>(sField.name());
588         const auto& sNamedValues = sField.namedValues();
589         dField.namedValues.resize(sNamedValues.size());
590         size_t j = 0;
591         for (const auto& sNamedValue : sNamedValues) {
592             auto& dNamedValue = dField.namedValues[j++];
593             dNamedValue.name = static_cast<decltype(dNamedValue.name)>(sNamedValue.first);
594             dNamedValue.value = static_cast<decltype(dNamedValue.value)>(
595                     sNamedValue.second.u64);
596         }
597     }
598     return true;
599 }
600 
601 // StructDescriptor -> C2StructDescriptor
602 template <typename StructDescriptor>
objcpy(std::unique_ptr<C2StructDescriptor> * d,const StructDescriptor & s)603 bool objcpy(std::unique_ptr<C2StructDescriptor> *d, const StructDescriptor &s) {
604     C2Param::CoreIndex dIndex = C2Param::CoreIndex(static_cast<uint32_t>(s.type));
605     std::vector<C2FieldDescriptor> dFields;
606     dFields.reserve(s.fields.size());
607     for (const auto &sField : s.fields) {
608         C2FieldDescriptor dField = {
609             static_cast<uint32_t>(sField.type),
610             static_cast<uint32_t>(sField.extent),
611             sField.name,
612             GetOffsetFromFieldId(sField.fieldId),
613             GetSizeFromFieldId(sField.fieldId) };
614         C2FieldDescriptor::NamedValuesType namedValues;
615         namedValues.reserve(sField.namedValues.size());
616         for (const auto& sNamedValue : sField.namedValues) {
617             namedValues.emplace_back(
618                 sNamedValue.name,
619                 C2Value::Primitive(static_cast<uint64_t>(sNamedValue.value)));
620         }
621         _C2ParamInspector::AddNamedValues(dField, std::move(namedValues));
622         dFields.emplace_back(dField);
623     }
624     *d = std::make_unique<C2StructDescriptor>(
625             _C2ParamInspector::CreateStructDescriptor(dIndex, std::move(dFields)));
626     return true;
627 }
628 
629 constexpr size_t PARAMS_ALIGNMENT = 8;  // 64-bit alignment
630 static_assert(PARAMS_ALIGNMENT % alignof(C2Param) == 0, "C2Param alignment mismatch");
631 static_assert(PARAMS_ALIGNMENT % alignof(C2Info) == 0, "C2Param alignment mismatch");
632 static_assert(PARAMS_ALIGNMENT % alignof(C2Tuning) == 0, "C2Param alignment mismatch");
633 
634 template <typename Params>
635 struct _ParamsBlobHelper { typedef Params BlobType; };
636 
637 template <typename Params>
638 using ParamsBlobType = typename _ParamsBlobHelper<Params>::BlobType;
639 
640 template <typename Params>
GetBlob(const Params & params)641 const ParamsBlobType<Params> &GetBlob(const Params &params) {
642     return params;
643 }
644 
645 template <typename Params>
GetBlob(Params * params)646 ParamsBlobType<Params> *GetBlob(Params *params) {
647     return params;
648 }
649 
650 // Params -> std::vector<C2Param*>
651 template <typename Params>
parseParamsBlob(std::vector<C2Param * > * params,const Params & paramsBlob)652 bool parseParamsBlob(std::vector<C2Param*> *params, const Params &paramsBlob) {
653     // assuming blob is const here
654     const ParamsBlobType<Params> &blob = GetBlob(paramsBlob);
655     size_t size = blob.size();
656     size_t ix = 0;
657     size_t old_ix = 0;
658     const uint8_t *data = blob.data();
659     C2Param *p = nullptr;
660 
661     do {
662         p = C2ParamUtils::ParseFirst(data + ix, size - ix);
663         if (p) {
664             params->emplace_back(p);
665             old_ix = ix;
666             ix += p->size();
667             ix = align(ix, PARAMS_ALIGNMENT);
668             if (ix <= old_ix || ix > size) {
669                 android_errorWriteLog(0x534e4554, "238083570");
670                 break;
671             }
672         }
673     } while (p);
674 
675     if (ix != size) {
676         LOG(ERROR) << "parseParamsBlob -- inconsistent sizes.";
677         return false;
678     }
679     return true;
680 }
681 
682 /**
683  * Concatenates a list of C2Params into a params blob. T is a container type
684  * whose member type is compatible with C2Param*.
685  *
686  * \param[out] blob target blob
687  * \param[in] params parameters to concatenate
688  * \retval C2_OK if the blob was successfully created
689  * \retval C2_BAD_VALUE if the blob was not successful created (this only
690  *         happens if the parameters were not const)
691  */
692 template <typename Params, typename T>
_createParamsBlob(Params * paramsBlob,const T & params)693 bool _createParamsBlob(Params *paramsBlob, const T &params) {
694     // assuming the parameter values are const
695     size_t size = 0;
696     for (const auto &p : params) {
697         if (!p) {
698             continue;
699         }
700         size += p->size();
701         size = align(size, PARAMS_ALIGNMENT);
702     }
703     ParamsBlobType<Params> *blob = GetBlob(paramsBlob);
704     blob->resize(size);
705     size_t ix = 0;
706     for (const auto &p : params) {
707         if (!p) {
708             continue;
709         }
710         // NEVER overwrite even if param values (e.g. size) changed
711         size_t paramSize = std::min(p->size(), size - ix);
712         std::copy(
713                 reinterpret_cast<const uint8_t*>(&*p),
714                 reinterpret_cast<const uint8_t*>(&*p) + paramSize,
715                 &(*blob)[ix]);
716         ix += paramSize;
717         ix = align(ix, PARAMS_ALIGNMENT);
718     }
719     blob->resize(ix);
720     if (ix != size) {
721         LOG(ERROR) << "createParamsBlob -- inconsistent sizes.";
722         return false;
723     }
724     return true;
725 }
726 
727 /**
728  * Parses a params blob and create a vector of new T objects that contain copies
729  * of the params in the blob. T is C2Param or its compatible derived class.
730  *
731  * \param[out] params the resulting vector
732  * \param[in] blob parameter blob to parse
733  * \retval C2_OK if the full blob was parsed and params was constructed
734  * \retval C2_BAD_VALUE otherwise
735  */
736 template <typename Params, typename T>
_copyParamsFromBlob(std::vector<std::unique_ptr<T>> * params,const Params & paramsBlob)737 bool _copyParamsFromBlob(
738         std::vector<std::unique_ptr<T>>* params,
739         const Params &paramsBlob) {
740     const ParamsBlobType<Params> &blob = GetBlob(paramsBlob);
741     std::vector<C2Param*> paramPointers;
742     if (!parseParamsBlob(&paramPointers, blob)) {
743         LOG(ERROR) << "copyParamsFromBlob -- failed to parse.";
744         return false;
745     }
746 
747     params->resize(paramPointers.size());
748     size_t i = 0;
749     for (C2Param* const& paramPointer : paramPointers) {
750         if (!paramPointer) {
751             LOG(ERROR) << "copyParamsFromBlob -- null paramPointer.";
752             return false;
753         }
754         (*params)[i++].reset(reinterpret_cast<T*>(
755                 C2Param::Copy(*paramPointer).release()));
756     }
757     return true;
758 }
759 
760 // Params -> update std::vector<std::unique_ptr<C2Param>>
761 template <typename Params>
updateParamsFromBlob(const std::vector<C2Param * > & params,const Params & paramsBlob)762 bool updateParamsFromBlob(
763         const std::vector<C2Param*>& params,
764         const Params& paramsBlob) {
765     const ParamsBlobType<Params> &blob = GetBlob(paramsBlob);
766     std::unordered_map<uint32_t, C2Param*> index2param;
767     for (C2Param* const& param : params) {
768         if (!param) {
769             LOG(ERROR) << "updateParamsFromBlob -- null output param.";
770             return false;
771         }
772         if (index2param.find(param->index()) == index2param.end()) {
773             index2param.emplace(param->index(), param);
774         }
775     }
776 
777     std::vector<C2Param*> paramPointers;
778     if (!parseParamsBlob(&paramPointers, blob)) {
779         LOG(ERROR) << "updateParamsFromBlob -- failed to parse.";
780         return false;
781     }
782 
783     for (C2Param* const& paramPointer : paramPointers) {
784         if (!paramPointer) {
785             LOG(ERROR) << "updateParamsFromBlob -- null input param.";
786             return false;
787         }
788         decltype(index2param)::iterator i = index2param.find(
789                 paramPointer->index());
790         if (i == index2param.end()) {
791             LOG(DEBUG) << "updateParamsFromBlob -- index "
792                        << paramPointer->index() << " not found. Skipping...";
793             continue;
794         }
795         if (!i->second->updateFrom(*paramPointer)) {
796             LOG(ERROR) << "updateParamsFromBlob -- size mismatch: "
797                        << params.size() << " vs " << paramPointer->size()
798                        << " (index = " << i->first << ").";
799             return false;
800         }
801     }
802     return true;
803 }
804 
805 }  // namespace android
806 
807 #endif  // CODEC2_COMMON_PARAM_TYPES_H
808