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>> ¶mDescs) {
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 ¶ms,
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 ¶ms,
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> ¶m : *vec) {
312 if (param && *param) {
313 paramsMap[param->index()] = ¶m;
314 }
315 }
316
317 parseMessageAndDoWork(
318 params,
319 [¶msMap](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 ¶ms,
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>> ¶ms_) 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*> ¶ms) 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