• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 //#define LOG_NDEBUG 0
18 #define LOG_TAG "ReflectedParamUpdater"
19 #include <utils/Log.h>
20 
21 #include <iostream>
22 #include <set>
23 #include <sstream>
24 
25 #include <C2Debug.h>
26 #include <C2ParamInternal.h>
27 
28 #include <media/stagefright/foundation/ABuffer.h>
29 #include <media/stagefright/foundation/ADebug.h>
30 #include <media/stagefright/foundation/AString.h>
31 #include <media/stagefright/foundation/hexdump.h>
32 
33 #include "ReflectedParamUpdater.h"
34 
35 namespace android {
36 
debugString(size_t indent_) const37 std::string ReflectedParamUpdater::Dict::debugString(size_t indent_) const {
38     std::string indent(indent_, ' ');
39     std::stringstream s;
40     s << "Dict {" << std::endl;
41 
42     for (const auto &it : *this) {
43         s << indent << "  ";
44 
45         C2Value c2Value;
46         int32_t int32Value;
47         uint32_t uint32Value;
48         int64_t int64Value;
49         uint64_t uint64Value;
50         float floatValue;
51         sp<ABuffer> bufValue;
52         AString strValue;
53         if (it.second.find(&c2Value)) {
54             switch (c2Value.type()) {
55                 case C2Value::INT32:
56                     (void)c2Value.get(&int32Value);
57                     s << "c2::i32 " << it.first << " = " << int32Value;
58                     break;
59                 case C2Value::UINT32:
60                     (void)c2Value.get(&uint32Value);
61                     s << "c2::u32 " << it.first << " = " << uint32Value;
62                     break;
63                 case C2Value::CNTR32:
64                     // dump counter value as unsigned
65                     (void)c2Value.get((c2_cntr32_t*)&uint32Value);
66                     s << "c2::c32 " << it.first << " = " << uint32Value;
67                     break;
68                 case C2Value::INT64:
69                     (void)c2Value.get(&int64Value);
70                     s << "c2::i64 " << it.first << " = " << int64Value;
71                     break;
72                 case C2Value::UINT64:
73                     (void)c2Value.get(&uint64Value);
74                     s << "c2::u64 " << it.first << " = " << uint64Value;
75                     break;
76                 case C2Value::CNTR64:
77                     // dump counter value as unsigned
78                     (void)c2Value.get((c2_cntr64_t*)&uint64Value);
79                     s << "c2::c64 " << it.first << " = " << uint64Value;
80                     break;
81                 case C2Value::FLOAT:
82                     (void)c2Value.get(&floatValue);
83                     s << "c2::float " << it.first << " = " << floatValue;
84                     break;
85                 default:
86                     // dump unsupported values for debugging, these should not be used
87                     s << "c2::unsupported " << it.first;
88             }
89         } else if (it.second.find(&int32Value)) {
90             s << "int32_t " << it.first << " = " << int32Value;
91         } else if (it.second.find(&int64Value)) {
92             s << "int64_t " << it.first << " = " << int64Value;
93         } else if (it.second.find(&strValue)) {
94             s << "string " << it.first << " = \"" << strValue.c_str() << "\"";
95         } else if (it.second.find(&bufValue)) {
96             s << "Buffer " << it.first << " = ";
97             if (bufValue != nullptr && bufValue->data() != nullptr && bufValue->size() <= 64) {
98                 s << "{" << std::endl;
99                 AString tmp;
100                 hexdump(bufValue->data(), bufValue->size(), indent_ + 4, &tmp);
101                 s << tmp.c_str() << indent << "  }";
102             } else {
103                 s << (void*)bufValue.get();
104             }
105         } else {
106             // dump unsupported values for debugging, this should never happen.
107             s << "unsupported " << it.first;
108         }
109         s << std::endl;
110     }
111     s << indent << "}";
112 
113     return s.str();
114 }
115 
addParamDesc(const std::shared_ptr<C2ParamReflector> & reflector,const std::vector<std::shared_ptr<C2ParamDescriptor>> & paramDescs)116 void ReflectedParamUpdater::addParamDesc(
117         const std::shared_ptr<C2ParamReflector> &reflector,
118         const std::vector<std::shared_ptr<C2ParamDescriptor>> &paramDescs) {
119     for (const std::shared_ptr<C2ParamDescriptor> &desc : paramDescs) {
120         std::unique_ptr<C2StructDescriptor> structDesc = reflector->describe(
121                 desc->index().coreIndex());
122         if (structDesc == nullptr) {
123             ALOGD("Could not describe %s", desc->name().c_str());
124             continue;
125         }
126         addParamDesc(desc, *structDesc, reflector, true /* markVendor */);
127     }
128 
129     // TEMP: also add vendor parameters as non-vendor
130     for (const std::shared_ptr<C2ParamDescriptor> &desc : paramDescs) {
131         if (!desc->index().isVendor()) {
132             continue;
133         }
134         std::unique_ptr<C2StructDescriptor> structDesc = reflector->describe(
135                 desc->index().coreIndex());
136         if (structDesc) {
137             addParamDesc(desc, *structDesc, reflector, false /* markVendor */);
138         }
139     }
140 }
141 
addParamStructDesc(std::shared_ptr<C2ParamDescriptor> desc,C2String path,size_t offset,const C2StructDescriptor & structDesc,const std::shared_ptr<C2ParamReflector> & reflector)142 void ReflectedParamUpdater::addParamStructDesc(
143         std::shared_ptr<C2ParamDescriptor> desc,
144         C2String path,
145         size_t offset,
146         const C2StructDescriptor &structDesc,
147         const std::shared_ptr<C2ParamReflector> &reflector) {
148     for (auto it = structDesc.begin(); it != structDesc.end(); ++it) {
149         C2String fieldName = path + "." + it->name();
150         if (it->type() & C2FieldDescriptor::STRUCT_FLAG) {
151             if (reflector == nullptr || it->extent() != 1) {
152                 ALOGD("ignored struct field %s", fieldName.c_str());
153                 continue;
154             }
155             std::unique_ptr<C2StructDescriptor> structDesc_ = reflector->describe(
156                     C2Param::CoreIndex(it->type()).coreIndex());
157             if (structDesc_ == nullptr) {
158                 ALOGD("Could not describe structure of %s", fieldName.c_str());
159                 continue;
160             }
161             addParamStructDesc(desc, fieldName, offset + _C2ParamInspector::GetOffset(*it),
162                                *structDesc_, reflector);
163             continue;
164         }
165 
166         // verify extent and type
167         switch (it->type()) {
168             case C2FieldDescriptor::INT32:
169             case C2FieldDescriptor::UINT32:
170             case C2FieldDescriptor::CNTR32:
171             case C2FieldDescriptor::INT64:
172             case C2FieldDescriptor::UINT64:
173             case C2FieldDescriptor::CNTR64:
174             case C2FieldDescriptor::FLOAT:
175                 if (it->extent() != 1) {
176                     ALOGD("extent() != 1 for single value type: %s", fieldName.c_str());
177                     continue;
178                 }
179                 break;
180             case C2FieldDescriptor::STRING:
181             case C2FieldDescriptor::BLOB:
182                 break;
183 
184             default:
185                 ALOGD("Unrecognized type: %s", fieldName.c_str());
186                 continue;
187         }
188 
189         ALOGV("%s registered", fieldName.c_str());
190         // TODO: get the proper size by iterating through the fields.
191         // only insert fields the very first time
192         mMap.emplace(fieldName, FieldDesc {
193             desc,
194             std::make_unique<C2FieldDescriptor>(
195                     it->type(), it->extent(), it->name(),
196                     _C2ParamInspector::GetOffset(*it),
197                     _C2ParamInspector::GetSize(*it)),
198             offset,
199         });
200     }
201 }
202 
addParamDesc(std::shared_ptr<C2ParamDescriptor> desc,const C2StructDescriptor & structDesc,const std::shared_ptr<C2ParamReflector> & reflector,bool markVendor)203 void ReflectedParamUpdater::addParamDesc(
204         std::shared_ptr<C2ParamDescriptor> desc, const C2StructDescriptor &structDesc,
205         const std::shared_ptr<C2ParamReflector> &reflector, bool markVendor) {
206     C2String paramName = desc->name();
207 
208     // prefix vendor parameters
209     if (desc->index().isVendor() && markVendor) {
210         paramName = "vendor." + paramName;
211     }
212     mParamNames.emplace(desc->index(), paramName);
213 
214     // also allow setting whole parameters in a binary fashion via ByteBuffer
215     // this is opt-in for now
216     auto it = mWholeParams.find(paramName);
217     if (it != mWholeParams.end() && it->second.coreIndex() == desc->index().coreIndex()) {
218         mMap.emplace(paramName, FieldDesc{ desc, nullptr, 0 /* offset */ });
219         // don't add fields of whole parameters.
220         return;
221     }
222 
223     addParamStructDesc(desc, paramName, 0 /* offset */, structDesc, reflector);
224 }
225 
supportWholeParam(std::string name,C2Param::CoreIndex index)226 void ReflectedParamUpdater::supportWholeParam(std::string name, C2Param::CoreIndex index) {
227     mWholeParams.emplace(name, index);
228 }
229 
getParamName(C2Param::Index index) const230 std::string ReflectedParamUpdater::getParamName(C2Param::Index index) const {
231     auto it = mParamNames.find(index);
232     if (it != mParamNames.end()) {
233         return it->second;
234     }
235 
236     std::stringstream ret;
237     ret << "<unknown " << index << ">";
238     return ret.str();
239 }
240 
getParamIndicesFromMessage(const Dict & params,std::vector<C2Param::Index> * vec) const241 void ReflectedParamUpdater::getParamIndicesFromMessage(
242         const Dict &params,
243         std::vector<C2Param::Index> *vec /* nonnull */) const {
244     CHECK(vec != nullptr);
245     vec->clear();
246     std::set<C2Param::Index> indices;
247     parseMessageAndDoWork(
248             params,
249             [&indices](const std::string &, const FieldDesc &desc, const void *, size_t) {
250                 indices.insert(desc.paramDesc->index());
251             });
252     for (const C2Param::Index &index : indices) {
253         vec->push_back(index);
254     }
255 }
256 
getParamIndicesForKeys(const std::vector<std::string> & keys,std::vector<C2Param::Index> * vec) const257 void ReflectedParamUpdater::getParamIndicesForKeys(
258         const std::vector<std::string> &keys,
259         std::vector<C2Param::Index> *vec /* nonnull */) const {
260     CHECK(vec != nullptr);
261     vec->clear();
262     std::set<C2Param::Index> indices;
263 
264     std::set<std::string> keyMap(keys.begin(), keys.end());
265 
266     ALOGV("in getParamIndicesForKeys with %zu keys and map of %zu entries",
267             keyMap.size(), mMap.size());
268     for (const std::pair<const std::string, FieldDesc> &kv : mMap) {
269         const std::string &name = kv.first;
270         const FieldDesc &desc = kv.second;
271         ALOGV("count of %s is %zu", name.c_str(), keyMap.count(name));
272         if (keyMap.count(name) > 0) {
273             indices.insert(desc.paramDesc->index());
274         }
275     }
276 
277     for (const C2Param::Index &index : indices) {
278         vec->push_back(index);
279     }
280 }
281 
updateParamsFromMessage(const Dict & params,std::vector<std::unique_ptr<C2Param>> * vec) const282 void ReflectedParamUpdater::updateParamsFromMessage(
283         const Dict &params,
284         std::vector<std::unique_ptr<C2Param>> *vec /* nonnull */) const {
285     CHECK(vec != nullptr);
286 
287     std::map<C2Param::Index, std::unique_ptr<C2Param>*> paramsMap;
288     for (std::unique_ptr<C2Param> &param : *vec) {
289         if (param && *param) {
290             paramsMap[param->index()] = &param;
291         }
292     }
293 
294     parseMessageAndDoWork(
295             params,
296             [&paramsMap](const std::string &name, const FieldDesc &desc, const void *ptr, size_t size) {
297                 std::unique_ptr<C2Param> *param = nullptr;
298                 auto paramIt = paramsMap.find(desc.paramDesc->index());
299                 if (paramIt == paramsMap.end()) {
300                     ALOGD("%s found, but param #%d isn't present to update",
301                             name.c_str(), (int32_t)desc.paramDesc->index());
302                     return;
303                 }
304                 param = paramIt->second;
305 
306                 struct _C2Param : public C2Param {
307                     using C2Param::C2Param;
308                     _C2Param(uint32_t size, uint32_t index) : C2Param(size, index) { }
309                 };
310 
311                 // we will handle whole param updates as part of a flexible param update using
312                 // a zero offset.
313                 size_t offset = 0;
314                 size_t minOffset = 0;
315 
316                 // if this descriptor has a field, use the offset and size and ensure that offset
317                 // is not part of the header
318                 if (desc.fieldDesc) {
319                     minOffset = sizeof(C2Param);
320                     offset = sizeof(C2Param) + desc.offset
321                             + _C2ParamInspector::GetOffset(*desc.fieldDesc);
322                 }
323 
324                 // reallocate or trim flexible param (or whole param) as necessary
325                 if (!desc.fieldDesc /* whole param */ || desc.fieldDesc->extent() == 0) {
326                     // reallocate param if more space is needed
327                     if (param->get()->size() < offset + size) {
328                         if (size > INT32_MAX - offset || offset < minOffset) {
329                             // size too long or offset too early - abandon
330                             return;
331                         }
332                         C2Param *newParam = (C2Param *)::operator new(offset + size);
333                         new (newParam) _C2Param(offset + size, param->get()->index());
334                         if (offset > sizeof(C2Param)) {
335                             memcpy(newParam + 1, param->get() + 1, offset - sizeof(C2Param));
336                         }
337                         param->reset(newParam);
338                     } else if (param->get()->size() > offset + size) {
339                         // trim parameter size
340                         _C2ParamInspector::TrimParam(param->get(), offset + size);
341                     }
342                 } else if (desc.fieldDesc->type() == C2FieldDescriptor::BLOB) {
343                     // zero fill blobs if updating with smaller blob
344                     if (desc.fieldDesc->extent() > size) {
345                         memset((uint8_t *)(param->get()) + offset + size, 0,
346                                desc.fieldDesc->extent() - size);
347                     }
348                 }
349 
350                 memcpy((uint8_t *)(param->get()) + offset, ptr, size);
351             });
352 }
353 
parseMessageAndDoWork(const Dict & params,std::function<void (const std::string &,const FieldDesc &,const void *,size_t)> work) const354 void ReflectedParamUpdater::parseMessageAndDoWork(
355         const Dict &params,
356         std::function<void(const std::string &, const FieldDesc &, const void *, size_t)> work) const {
357     for (const std::pair<const std::string, FieldDesc> &kv : mMap) {
358         const std::string &name = kv.first;
359         const FieldDesc &desc = kv.second;
360         auto param = params.find(name);
361         if (param == params.end()) {
362             continue;
363         }
364 
365         // handle whole parameters
366         if (!desc.fieldDesc) {
367             sp<ABuffer> tmp;
368             if (param->second.find(&tmp) && tmp != nullptr) {
369                 C2Param *tmpAsParam = C2Param::From(tmp->data(), tmp->size());
370                 if (tmpAsParam && tmpAsParam->type().type() == desc.paramDesc->index().type()) {
371                     work(name, desc, tmp->data(), tmp->size());
372                 } else {
373                     ALOGD("Param blob does not match param for '%s' (%p, %x vs %x)",
374                             name.c_str(), tmpAsParam, tmpAsParam ? tmpAsParam->type().type() : 0xDEADu,
375                             desc.paramDesc->index().type());
376                 }
377             }
378             continue;
379         }
380 
381         int32_t int32Value;
382         int64_t int64Value;
383         C2Value c2Value;
384 
385         C2FieldDescriptor::type_t fieldType = desc.fieldDesc->type();
386         size_t fieldExtent = desc.fieldDesc->extent();
387         switch (fieldType) {
388             case C2FieldDescriptor::INT32:
389                 if ((param->second.find(&c2Value) && c2Value.get(&int32Value))
390                         || param->second.find(&int32Value)) {
391                     work(name, desc, &int32Value, sizeof(int32Value));
392                 }
393                 break;
394             case C2FieldDescriptor::UINT32:
395                 if ((param->second.find(&c2Value) && c2Value.get((uint32_t*)&int32Value))
396                         || param->second.find(&int32Value)) {
397                     work(name, desc, &int32Value, sizeof(int32Value));
398                 }
399                 break;
400             case C2FieldDescriptor::CNTR32:
401                 if ((param->second.find(&c2Value) && c2Value.get((c2_cntr32_t*)&int32Value))
402                         || param->second.find(&int32Value)) {
403                     work(name, desc, &int32Value, sizeof(int32Value));
404                 }
405                 break;
406             case C2FieldDescriptor::INT64:
407                 if ((param->second.find(&c2Value) && c2Value.get(&int64Value))
408                         || param->second.find(&int64Value)) {
409                     work(name, desc, &int64Value, sizeof(int64Value));
410                 }
411                 break;
412             case C2FieldDescriptor::UINT64:
413                 if ((param->second.find(&c2Value) && c2Value.get((uint64_t*)&int64Value))
414                         || param->second.find(&int64Value)) {
415                     work(name, desc, &int64Value, sizeof(int64Value));
416                 }
417                 break;
418             case C2FieldDescriptor::CNTR64:
419                 if ((param->second.find(&c2Value) && c2Value.get((c2_cntr64_t*)&int64Value))
420                         || param->second.find(&int64Value)) {
421                     work(name, desc, &int64Value, sizeof(int64Value));
422                 }
423                 break;
424             case C2FieldDescriptor::FLOAT: {
425                 float tmp;
426                 if (param->second.find(&c2Value) && c2Value.get(&tmp)) {
427                     work(name, desc, &tmp, sizeof(tmp));
428                 }
429                 break;
430             }
431             case C2FieldDescriptor::STRING: {
432                 AString tmp;
433                 if (!param->second.find(&tmp)) {
434                     break;
435                 }
436                 if (fieldExtent > 0 && tmp.size() >= fieldExtent) {
437                     AString truncated(tmp, 0, fieldExtent - 1);
438                     ALOGD("String value too long to fit: original \"%s\" truncated to \"%s\"",
439                             tmp.c_str(), truncated.c_str());
440                     tmp = truncated;
441                 }
442                 work(name, desc, tmp.c_str(), tmp.size() + 1);
443                 break;
444             }
445 
446             case C2FieldDescriptor::BLOB: {
447                 sp<ABuffer> tmp;
448                 if (!param->second.find(&tmp) || tmp == nullptr) {
449                     break;
450                 }
451 
452                 if (fieldExtent > 0 && tmp->size() > fieldExtent) {
453                     ALOGD("Blob value too long to fit. Truncating.");
454                     tmp->setRange(tmp->offset(), fieldExtent);
455                 }
456                 work(name, desc, tmp->data(), tmp->size());
457                 break;
458             }
459 
460             default:
461                 ALOGD("Unsupported data type for %s", name.c_str());
462                 break;
463         }
464     }
465 }
466 
467 ReflectedParamUpdater::Dict
getParams(const std::vector<std::unique_ptr<C2Param>> & params_) const468 ReflectedParamUpdater::getParams(const std::vector<std::unique_ptr<C2Param>> &params_) const {
469     std::vector<C2Param*> params;
470     params.resize(params_.size());
471     std::transform(params_.begin(), params_.end(), params.begin(),
472                    [](const std::unique_ptr<C2Param>& p) -> C2Param* { return p.get(); });
473     return getParams(params);
474 }
475 
476 ReflectedParamUpdater::Dict
getParams(const std::vector<C2Param * > & params) const477 ReflectedParamUpdater::getParams(const std::vector<C2Param*> &params) const {
478     Dict ret;
479 
480     // convert vector to map
481     std::map<C2Param::Index, C2Param *> paramsMap;
482     for (C2Param *param : params) {
483         if (param != nullptr && *param) {
484             paramsMap[param->index()] = param;
485         }
486     }
487 
488     for (const std::pair<const std::string, FieldDesc> &kv : mMap) {
489         const std::string &name = kv.first;
490         const FieldDesc &desc = kv.second;
491         if (paramsMap.count(desc.paramDesc->index()) == 0) {
492             continue;
493         }
494         C2Param *param = paramsMap[desc.paramDesc->index()];
495         Value value;
496 
497         // handle whole params first
498         if (!desc.fieldDesc) {
499             sp<ABuffer> buf = ABuffer::CreateAsCopy(param, param->size());
500             value.set(buf);
501             ret.emplace(name, value);
502             continue;
503         }
504 
505         size_t offset = sizeof(C2Param) + desc.offset
506                 + _C2ParamInspector::GetOffset(*desc.fieldDesc);
507         uint8_t *data = (uint8_t *)param + offset;
508         C2FieldDescriptor::type_t fieldType = desc.fieldDesc->type();
509         switch (fieldType) {
510             case C2FieldDescriptor::STRING: {
511                 size_t length = desc.fieldDesc->extent();
512                 if (length == 0) {
513                     length = param->size() - offset;
514                 }
515 
516                 if (param->size() < length || param->size() - length < offset) {
517                     ALOGD("param too small for string: length %zu size %zu offset %zu",
518                             length, param->size(), offset);
519                     break;
520                 }
521                 value.set(AString((char *)data, strnlen((char *)data, length)));
522                 break;
523             }
524 
525             case C2FieldDescriptor::BLOB: {
526                 size_t length = desc.fieldDesc->extent();
527                 if (length == 0) {
528                     length = param->size() - offset;
529                 }
530 
531                 if (param->size() < length || param->size() - length < offset) {
532                     ALOGD("param too small for blob: length %zu size %zu offset %zu",
533                             length, param->size(), offset);
534                     break;
535                 }
536 
537                 sp<ABuffer> buf = ABuffer::CreateAsCopy(data, length);
538                 value.set(buf);
539                 break;
540             }
541 
542             default: {
543                 size_t valueSize = C2Value::SizeFor((C2Value::type_t)fieldType);
544                 if (param->size() < valueSize || param->size() - valueSize < offset) {
545                     ALOGD("param too small for c2value: size %zu offset %zu",
546                             param->size(), offset);
547                     break;
548                 }
549 
550                 C2Value c2Value;
551                 switch (fieldType) {
552                     case C2FieldDescriptor::INT32:  c2Value = *((int32_t *)data); break;
553                     case C2FieldDescriptor::UINT32: c2Value = *((uint32_t *)data); break;
554                     case C2FieldDescriptor::CNTR32: c2Value = *((c2_cntr32_t *)data); break;
555                     case C2FieldDescriptor::INT64:  c2Value = *((int64_t *)data); break;
556                     case C2FieldDescriptor::UINT64: c2Value = *((uint64_t *)data); break;
557                     case C2FieldDescriptor::CNTR64: c2Value = *((c2_cntr64_t *)data); break;
558                     case C2FieldDescriptor::FLOAT:  c2Value = *((float *)data); break;
559                     default:
560                         ALOGD("Unsupported data type for %s", name.c_str());
561                         continue;
562                 }
563                 value.set(c2Value);
564             }
565         }
566         ret.emplace(name, value);
567     }
568     return ret;
569 }
570 
clear()571 void ReflectedParamUpdater::clear() {
572     mMap.clear();
573 }
574 
575 }  // namespace android
576