• 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 
addParamStructDesc(std::shared_ptr<C2ParamDescriptor> desc,C2String path,size_t offset,const C2StructDescriptor & structDesc,const std::shared_ptr<C2ParamReflector> & reflector)130 void ReflectedParamUpdater::addParamStructDesc(
131         std::shared_ptr<C2ParamDescriptor> desc,
132         C2String path,
133         size_t offset,
134         const C2StructDescriptor &structDesc,
135         const std::shared_ptr<C2ParamReflector> &reflector) {
136     for (auto it = structDesc.begin(); it != structDesc.end(); ++it) {
137         C2String fieldName = path + "." + it->name();
138         if (it->type() & C2FieldDescriptor::STRUCT_FLAG) {
139             if (reflector == nullptr || it->extent() != 1) {
140                 ALOGD("ignored struct field %s", fieldName.c_str());
141                 continue;
142             }
143             std::unique_ptr<C2StructDescriptor> structDesc_ = reflector->describe(
144                     C2Param::CoreIndex(it->type()).coreIndex());
145             if (structDesc_ == nullptr) {
146                 ALOGD("Could not describe structure of %s", fieldName.c_str());
147                 continue;
148             }
149             addParamStructDesc(desc, fieldName, offset + _C2ParamInspector::GetOffset(*it),
150                                *structDesc_, reflector);
151             continue;
152         }
153 
154         // verify extent and type
155         switch (it->type()) {
156             case C2FieldDescriptor::INT32:
157             case C2FieldDescriptor::UINT32:
158             case C2FieldDescriptor::CNTR32:
159             case C2FieldDescriptor::INT64:
160             case C2FieldDescriptor::UINT64:
161             case C2FieldDescriptor::CNTR64:
162             case C2FieldDescriptor::FLOAT:
163                 if (it->extent() != 1) {
164                     ALOGD("extent() != 1 for single value type: %s", fieldName.c_str());
165                     continue;
166                 }
167                 break;
168             case C2FieldDescriptor::STRING:
169             case C2FieldDescriptor::BLOB:
170                 break;
171 
172             default:
173                 ALOGD("Unrecognized type: %s", fieldName.c_str());
174                 continue;
175         }
176 
177         ALOGV("%s registered", fieldName.c_str());
178         // TODO: get the proper size by iterating through the fields.
179         // only insert fields the very first time
180         mMap.emplace(fieldName, FieldDesc {
181             desc,
182             std::make_unique<C2FieldDescriptor>(
183                     it->type(), it->extent(), it->name(),
184                     _C2ParamInspector::GetOffset(*it),
185                     _C2ParamInspector::GetSize(*it)),
186             offset,
187         });
188     }
189 }
190 
addParamDesc(std::shared_ptr<C2ParamDescriptor> desc,const C2StructDescriptor & structDesc,const std::shared_ptr<C2ParamReflector> & reflector,bool markVendor)191 void ReflectedParamUpdater::addParamDesc(
192         std::shared_ptr<C2ParamDescriptor> desc, const C2StructDescriptor &structDesc,
193         const std::shared_ptr<C2ParamReflector> &reflector, bool markVendor) {
194     C2String paramName = desc->name();
195 
196     // Do not reflect requested parameters
197     // TODO: split these once aliases are introduced into '.actual' and '.requested' and alias
198     // the name to '.actual'.
199     if (desc->index() & C2Param::CoreIndex::IS_REQUEST_FLAG) {
200         return;
201     }
202 
203     // prefix vendor parameters
204     if (desc->index().isVendor() && markVendor) {
205         paramName = "vendor." + paramName;
206     }
207     mParamNames.emplace(desc->index(), paramName);
208 
209     // also allow setting whole parameters in a binary fashion via ByteBuffer
210     // this is opt-in for now
211     auto it = mWholeParams.find(paramName);
212     if (it != mWholeParams.end() && it->second.coreIndex() == desc->index().coreIndex()) {
213         mMap.emplace(paramName, FieldDesc{ desc, nullptr, 0 /* offset */ });
214         // don't add fields of whole parameters.
215         return;
216     }
217 
218     addParamStructDesc(desc, paramName, 0 /* offset */, structDesc, reflector);
219 }
220 
supportWholeParam(std::string name,C2Param::CoreIndex index)221 void ReflectedParamUpdater::supportWholeParam(std::string name, C2Param::CoreIndex index) {
222     mWholeParams.emplace(name, index);
223 }
224 
getParamName(C2Param::Index index) const225 std::string ReflectedParamUpdater::getParamName(C2Param::Index index) const {
226     auto it = mParamNames.find(index);
227     if (it != mParamNames.end()) {
228         return it->second;
229     }
230 
231     std::stringstream ret;
232     ret << "<unknown " << index << ">";
233     return ret.str();
234 }
235 
getParamIndicesFromMessage(const Dict & params,std::vector<C2Param::Index> * vec) const236 void ReflectedParamUpdater::getParamIndicesFromMessage(
237         const Dict &params,
238         std::vector<C2Param::Index> *vec /* nonnull */) const {
239     CHECK(vec != nullptr);
240     vec->clear();
241     std::set<C2Param::Index> indices;
242     parseMessageAndDoWork(
243             params,
244             [&indices](const std::string &, const FieldDesc &desc, const void *, size_t) {
245                 indices.insert(desc.paramDesc->index());
246             });
247     for (const C2Param::Index &index : indices) {
248         vec->push_back(index);
249     }
250 }
251 
getParamIndicesForKeys(const std::vector<std::string> & keys,std::vector<C2Param::Index> * vec) const252 void ReflectedParamUpdater::getParamIndicesForKeys(
253         const std::vector<std::string> &keys,
254         std::vector<C2Param::Index> *vec /* nonnull */) const {
255     CHECK(vec != nullptr);
256     vec->clear();
257     std::set<C2Param::Index> indices;
258 
259     std::set<std::string> keyMap(keys.begin(), keys.end());
260 
261     ALOGV("in getParamIndicesForKeys with %zu keys and map of %zu entries",
262             keyMap.size(), mMap.size());
263     for (const std::pair<const std::string, FieldDesc> &kv : mMap) {
264         const std::string &name = kv.first;
265         const FieldDesc &desc = kv.second;
266         ALOGV("count of %s is %zu", name.c_str(), keyMap.count(name));
267         if (keyMap.count(name) > 0) {
268             indices.insert(desc.paramDesc->index());
269         }
270     }
271 
272     for (const C2Param::Index &index : indices) {
273         vec->push_back(index);
274     }
275 }
276 
getKeysForParamIndex(const C2Param::Index & index,std::vector<std::string> * keys) const277 void ReflectedParamUpdater::getKeysForParamIndex(
278         const C2Param::Index &index,
279         std::vector<std::string> *keys /* nonnull */) const {
280     CHECK(keys != nullptr);
281     keys->clear();
282     for (const std::pair<const std::string, FieldDesc> &kv : mMap) {
283         const std::string &name = kv.first;
284         const FieldDesc &desc = kv.second;
285         if (desc.paramDesc->index() == index) {
286             keys->push_back(name);
287         }
288     }
289 }
290 
getTypeForKey(const std::string & key) const291 C2FieldDescriptor::type_t ReflectedParamUpdater::getTypeForKey(
292         const std::string &key) const {
293     auto it = mMap.find(key);
294     if (it == mMap.end()) {
295         return C2FieldDescriptor::type_t(~0);
296     }
297 
298     if (it->second.fieldDesc) {
299         return it->second.fieldDesc->type();
300     }
301     // whole param is exposed as a blob
302     return C2FieldDescriptor::BLOB;
303 }
304 
updateParamsFromMessage(const Dict & params,std::vector<std::unique_ptr<C2Param>> * vec) const305 void ReflectedParamUpdater::updateParamsFromMessage(
306         const Dict &params,
307         std::vector<std::unique_ptr<C2Param>> *vec /* nonnull */) const {
308     CHECK(vec != nullptr);
309 
310     std::map<C2Param::Index, std::unique_ptr<C2Param>*> paramsMap;
311     for (std::unique_ptr<C2Param> &param : *vec) {
312         if (param && *param) {
313             paramsMap[param->index()] = &param;
314         }
315     }
316 
317     parseMessageAndDoWork(
318             params,
319             [&paramsMap](const std::string &name, const FieldDesc &desc, const void *ptr, size_t size) {
320                 std::unique_ptr<C2Param> *param = nullptr;
321                 auto paramIt = paramsMap.find(desc.paramDesc->index());
322                 if (paramIt == paramsMap.end()) {
323                     ALOGD("%s found, but param #%d isn't present to update",
324                             name.c_str(), (int32_t)desc.paramDesc->index());
325                     return;
326                 }
327                 param = paramIt->second;
328 
329                 struct _C2Param : public C2Param {
330                     using C2Param::C2Param;
331                     _C2Param(uint32_t size, uint32_t index) : C2Param(size, index) { }
332                 };
333 
334                 // we will handle whole param updates as part of a flexible param update using
335                 // a zero offset.
336                 size_t offset = 0;
337                 size_t minOffset = 0;
338 
339                 // if this descriptor has a field, use the offset and size and ensure that offset
340                 // is not part of the header
341                 if (desc.fieldDesc) {
342                     minOffset = sizeof(C2Param);
343                     offset = sizeof(C2Param) + desc.offset
344                             + _C2ParamInspector::GetOffset(*desc.fieldDesc);
345                 }
346 
347                 // reallocate or trim flexible param (or whole param) as necessary
348                 if (!desc.fieldDesc /* whole param */ || desc.fieldDesc->extent() == 0) {
349                     // reallocate param if more space is needed
350                     if (param->get()->size() < offset + size) {
351                         if (size > INT32_MAX - offset || offset < minOffset) {
352                             // size too long or offset too early - abandon
353                             return;
354                         }
355                         C2Param *newParam = (C2Param *)::operator new(offset + size);
356                         new (newParam) _C2Param(offset + size, param->get()->index());
357                         if (offset > sizeof(C2Param)) {
358                             memcpy(newParam + 1, param->get() + 1, offset - sizeof(C2Param));
359                         }
360                         param->reset(newParam);
361                     } else if (param->get()->size() > offset + size) {
362                         // trim parameter size
363                         _C2ParamInspector::TrimParam(param->get(), offset + size);
364                     }
365                 } else if (desc.fieldDesc->type() == C2FieldDescriptor::BLOB) {
366                     // zero fill blobs if updating with smaller blob
367                     if (desc.fieldDesc->extent() > size) {
368                         memset((uint8_t *)(param->get()) + offset + size, 0,
369                                desc.fieldDesc->extent() - size);
370                     }
371                 }
372 
373                 memcpy((uint8_t *)(param->get()) + offset, ptr, size);
374             });
375 }
376 
parseMessageAndDoWork(const Dict & params,std::function<void (const std::string &,const FieldDesc &,const void *,size_t)> work) const377 void ReflectedParamUpdater::parseMessageAndDoWork(
378         const Dict &params,
379         std::function<void(const std::string &, const FieldDesc &, const void *, size_t)> work) const {
380     for (const std::pair<const std::string, FieldDesc> &kv : mMap) {
381         const std::string &name = kv.first;
382         const FieldDesc &desc = kv.second;
383         auto param = params.find(name);
384         if (param == params.end()) {
385             continue;
386         }
387 
388         // handle whole parameters
389         if (!desc.fieldDesc) {
390             sp<ABuffer> tmp;
391             if (param->second.find(&tmp) && tmp != nullptr) {
392                 C2Param *tmpAsParam = C2Param::From(tmp->data(), tmp->size());
393                 if (tmpAsParam && tmpAsParam->type().type() == desc.paramDesc->index().type()) {
394                     work(name, desc, tmp->data(), tmp->size());
395                 } else {
396                     ALOGD("Param blob does not match param for '%s' (%p, %x vs %x)",
397                             name.c_str(), tmpAsParam, tmpAsParam ? tmpAsParam->type().type() : 0xDEADu,
398                             desc.paramDesc->index().type());
399                 }
400             }
401             continue;
402         }
403 
404         int32_t int32Value;
405         int64_t int64Value;
406         C2Value c2Value;
407 
408         C2FieldDescriptor::type_t fieldType = desc.fieldDesc->type();
409         size_t fieldExtent = desc.fieldDesc->extent();
410         switch (fieldType) {
411             case C2FieldDescriptor::INT32:
412                 if ((param->second.find(&c2Value) && c2Value.get(&int32Value))
413                         || param->second.find(&int32Value)) {
414                     work(name, desc, &int32Value, sizeof(int32Value));
415                 }
416                 break;
417             case C2FieldDescriptor::UINT32:
418                 if ((param->second.find(&c2Value) && c2Value.get((uint32_t*)&int32Value))
419                         || param->second.find(&int32Value)) {
420                     work(name, desc, &int32Value, sizeof(int32Value));
421                 }
422                 break;
423             case C2FieldDescriptor::CNTR32:
424                 if ((param->second.find(&c2Value) && c2Value.get((c2_cntr32_t*)&int32Value))
425                         || param->second.find(&int32Value)) {
426                     work(name, desc, &int32Value, sizeof(int32Value));
427                 }
428                 break;
429             case C2FieldDescriptor::INT64:
430                 if ((param->second.find(&c2Value) && c2Value.get(&int64Value))
431                         || param->second.find(&int64Value)) {
432                     work(name, desc, &int64Value, sizeof(int64Value));
433                 }
434                 break;
435             case C2FieldDescriptor::UINT64:
436                 if ((param->second.find(&c2Value) && c2Value.get((uint64_t*)&int64Value))
437                         || param->second.find(&int64Value)) {
438                     work(name, desc, &int64Value, sizeof(int64Value));
439                 }
440                 break;
441             case C2FieldDescriptor::CNTR64:
442                 if ((param->second.find(&c2Value) && c2Value.get((c2_cntr64_t*)&int64Value))
443                         || param->second.find(&int64Value)) {
444                     work(name, desc, &int64Value, sizeof(int64Value));
445                 }
446                 break;
447             case C2FieldDescriptor::FLOAT: {
448                 float tmp;
449                 if (param->second.find(&c2Value) && c2Value.get(&tmp)) {
450                     work(name, desc, &tmp, sizeof(tmp));
451                 }
452                 break;
453             }
454             case C2FieldDescriptor::STRING: {
455                 AString tmp;
456                 if (!param->second.find(&tmp)) {
457                     break;
458                 }
459                 if (fieldExtent > 0 && tmp.size() >= fieldExtent) {
460                     AString truncated(tmp, 0, fieldExtent - 1);
461                     ALOGD("String value too long to fit: original \"%s\" truncated to \"%s\"",
462                             tmp.c_str(), truncated.c_str());
463                     tmp = truncated;
464                 }
465                 work(name, desc, tmp.c_str(), tmp.size() + 1);
466                 break;
467             }
468 
469             case C2FieldDescriptor::BLOB: {
470                 sp<ABuffer> tmp;
471                 if (!param->second.find(&tmp) || tmp == nullptr) {
472                     break;
473                 }
474 
475                 if (fieldExtent > 0 && tmp->size() > fieldExtent) {
476                     ALOGD("Blob value too long to fit. Truncating.");
477                     tmp->setRange(tmp->offset(), fieldExtent);
478                 }
479                 work(name, desc, tmp->data(), tmp->size());
480                 break;
481             }
482 
483             default:
484                 ALOGD("Unsupported data type for %s", name.c_str());
485                 break;
486         }
487     }
488 }
489 
490 ReflectedParamUpdater::Dict
getParams(const std::vector<std::unique_ptr<C2Param>> & params_) const491 ReflectedParamUpdater::getParams(const std::vector<std::unique_ptr<C2Param>> &params_) const {
492     std::vector<C2Param*> params;
493     params.resize(params_.size());
494     std::transform(params_.begin(), params_.end(), params.begin(),
495                    [](const std::unique_ptr<C2Param>& p) -> C2Param* { return p.get(); });
496     return getParams(params);
497 }
498 
499 ReflectedParamUpdater::Dict
getParams(const std::vector<C2Param * > & params) const500 ReflectedParamUpdater::getParams(const std::vector<C2Param*> &params) const {
501     Dict ret;
502 
503     // convert vector to map
504     std::map<C2Param::Index, C2Param *> paramsMap;
505     for (C2Param *param : params) {
506         if (param != nullptr && *param) {
507             paramsMap[param->index()] = param;
508         }
509     }
510 
511     for (const std::pair<const std::string, FieldDesc> &kv : mMap) {
512         const std::string &name = kv.first;
513         const FieldDesc &desc = kv.second;
514         if (paramsMap.count(desc.paramDesc->index()) == 0) {
515             continue;
516         }
517         C2Param *param = paramsMap[desc.paramDesc->index()];
518         Value value;
519 
520         // handle whole params first
521         if (!desc.fieldDesc) {
522             sp<ABuffer> buf = ABuffer::CreateAsCopy(param, param->size());
523             value.set(buf);
524             ret.emplace(name, value);
525             continue;
526         }
527 
528         size_t offset = sizeof(C2Param) + desc.offset
529                 + _C2ParamInspector::GetOffset(*desc.fieldDesc);
530         uint8_t *data = (uint8_t *)param + offset;
531         C2FieldDescriptor::type_t fieldType = desc.fieldDesc->type();
532         switch (fieldType) {
533             case C2FieldDescriptor::STRING: {
534                 size_t length = desc.fieldDesc->extent();
535                 if (length == 0) {
536                     length = param->size() - offset;
537                 }
538 
539                 if (param->size() < length || param->size() - length < offset) {
540                     ALOGD("param too small for string: length %zu size %zu offset %zu",
541                             length, param->size(), offset);
542                     break;
543                 }
544                 value.set(AString((char *)data, strnlen((char *)data, length)));
545                 break;
546             }
547 
548             case C2FieldDescriptor::BLOB: {
549                 size_t length = desc.fieldDesc->extent();
550                 if (length == 0) {
551                     length = param->size() - offset;
552                 }
553 
554                 if (param->size() < length || param->size() - length < offset) {
555                     ALOGD("param too small for blob: length %zu size %zu offset %zu",
556                             length, param->size(), offset);
557                     break;
558                 }
559 
560                 sp<ABuffer> buf = ABuffer::CreateAsCopy(data, length);
561                 value.set(buf);
562                 break;
563             }
564 
565             default: {
566                 size_t valueSize = C2Value::SizeFor((C2Value::type_t)fieldType);
567                 if (param->size() < valueSize || param->size() - valueSize < offset) {
568                     ALOGD("param too small for c2value: size %zu offset %zu",
569                             param->size(), offset);
570                     break;
571                 }
572 
573                 C2Value c2Value;
574                 switch (fieldType) {
575                     case C2FieldDescriptor::INT32:  c2Value = *((int32_t *)data); break;
576                     case C2FieldDescriptor::UINT32: c2Value = *((uint32_t *)data); break;
577                     case C2FieldDescriptor::CNTR32: c2Value = *((c2_cntr32_t *)data); break;
578                     case C2FieldDescriptor::INT64:  c2Value = *((int64_t *)data); break;
579                     case C2FieldDescriptor::UINT64: c2Value = *((uint64_t *)data); break;
580                     case C2FieldDescriptor::CNTR64: c2Value = *((c2_cntr64_t *)data); break;
581                     case C2FieldDescriptor::FLOAT:  c2Value = *((float *)data); break;
582                     default:
583                         ALOGD("Unsupported data type for %s", name.c_str());
584                         continue;
585                 }
586                 value.set(c2Value);
587             }
588         }
589         ret.emplace(name, value);
590     }
591     return ret;
592 }
593 
clear()594 void ReflectedParamUpdater::clear() {
595     mMap.clear();
596 }
597 
598 }  // namespace android
599