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 != NULL && bufValue->data() != NULL && 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 // 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 addParamStructDesc(desc, paramName, 0 /* offset */, structDesc, reflector);
215 }
216
getParamName(C2Param::Index index) const217 std::string ReflectedParamUpdater::getParamName(C2Param::Index index) const {
218 auto it = mParamNames.find(index);
219 if (it != mParamNames.end()) {
220 return it->second;
221 }
222
223 std::stringstream ret;
224 ret << "<unknown " << index << ">";
225 return ret.str();
226 }
227
getParamIndicesFromMessage(const Dict & params,std::vector<C2Param::Index> * vec) const228 void ReflectedParamUpdater::getParamIndicesFromMessage(
229 const Dict ¶ms,
230 std::vector<C2Param::Index> *vec /* nonnull */) const {
231 CHECK(vec != nullptr);
232 vec->clear();
233 std::set<C2Param::Index> indices;
234 parseMessageAndDoWork(
235 params,
236 [&indices](const std::string &, const FieldDesc &desc, const void *, size_t) {
237 indices.insert(desc.paramDesc->index());
238 });
239 for (const C2Param::Index &index : indices) {
240 vec->push_back(index);
241 }
242 }
243
getParamIndicesForKeys(const std::vector<std::string> & keys,std::vector<C2Param::Index> * vec) const244 void ReflectedParamUpdater::getParamIndicesForKeys(
245 const std::vector<std::string> &keys,
246 std::vector<C2Param::Index> *vec /* nonnull */) const {
247 CHECK(vec != nullptr);
248 vec->clear();
249 std::set<C2Param::Index> indices;
250
251 std::set<std::string> keyMap(keys.begin(), keys.end());
252
253 ALOGV("in getParamIndicesForKeys with %zu keys and map of %zu entries",
254 keyMap.size(), mMap.size());
255 for (const std::pair<const std::string, FieldDesc> &kv : mMap) {
256 const std::string &name = kv.first;
257 const FieldDesc &desc = kv.second;
258 ALOGV("count of %s is %zu", name.c_str(), keyMap.count(name));
259 if (keyMap.count(name) > 0) {
260 indices.insert(desc.paramDesc->index());
261 }
262 }
263
264 for (const C2Param::Index &index : indices) {
265 vec->push_back(index);
266 }
267 }
268
updateParamsFromMessage(const Dict & params,std::vector<std::unique_ptr<C2Param>> * vec) const269 void ReflectedParamUpdater::updateParamsFromMessage(
270 const Dict ¶ms,
271 std::vector<std::unique_ptr<C2Param>> *vec /* nonnull */) const {
272 CHECK(vec != nullptr);
273
274 std::map<C2Param::Index, std::unique_ptr<C2Param>*> paramsMap;
275 for (std::unique_ptr<C2Param> ¶m : *vec) {
276 if (param && *param) {
277 paramsMap[param->index()] = ¶m;
278 }
279 }
280
281 parseMessageAndDoWork(
282 params,
283 [¶msMap](const std::string &name, const FieldDesc &desc, const void *ptr, size_t size) {
284 size_t offset = sizeof(C2Param) + desc.offset
285 + _C2ParamInspector::GetOffset(*desc.fieldDesc);
286 std::unique_ptr<C2Param> *param = nullptr;
287 auto paramIt = paramsMap.find(desc.paramDesc->index());
288 if (paramIt == paramsMap.end()) {
289 ALOGD("%s found, but param #%d isn't present to update",
290 name.c_str(), (int32_t)desc.paramDesc->index());
291 return;
292 }
293 param = paramIt->second;
294
295 // reallocate or trim flexible param as necessary
296 if (desc.fieldDesc->extent() == 0) {
297 struct _C2Param : public C2Param {
298 using C2Param::C2Param;
299 _C2Param(uint32_t size, uint32_t index) : C2Param(size, index) { }
300 };
301 // reallocate param if more space is needed
302 if (param->get()->size() < offset + size) {
303 if (size > INT32_MAX - offset || offset < sizeof(C2Param)) {
304 // size too long or offset too early - abandon
305 return;
306 }
307 C2Param *newParam = (C2Param *)::operator new(offset + size);
308 new (newParam) _C2Param(offset + size, param->get()->index());
309 memcpy(newParam + 1, param->get() + 1, offset - sizeof(C2Param));
310 param->reset(newParam);
311 } else if (param->get()->size() > offset + size) {
312 // trim parameter size
313 _C2ParamInspector::TrimParam(param->get(), offset + size);
314 }
315 } else if (desc.fieldDesc->type() == C2FieldDescriptor::BLOB) {
316 // zero fill blobs if updating with smaller blob
317 if (desc.fieldDesc->extent() > size) {
318 memset((uint8_t *)(param->get()) + offset + size, 0,
319 desc.fieldDesc->extent() - size);
320 }
321 }
322
323 memcpy((uint8_t *)(param->get()) + offset, ptr, size);
324 });
325 }
326
parseMessageAndDoWork(const Dict & params,std::function<void (const std::string &,const FieldDesc &,const void *,size_t)> work) const327 void ReflectedParamUpdater::parseMessageAndDoWork(
328 const Dict ¶ms,
329 std::function<void(const std::string &, const FieldDesc &, const void *, size_t)> work) const {
330 for (const std::pair<const std::string, FieldDesc> &kv : mMap) {
331 const std::string &name = kv.first;
332 const FieldDesc &desc = kv.second;
333 auto param = params.find(name);
334 if (param == params.end()) {
335 continue;
336 }
337
338 int32_t int32Value;
339 int64_t int64Value;
340 C2Value c2Value;
341
342 C2FieldDescriptor::type_t fieldType = desc.fieldDesc->type();
343 size_t fieldExtent = desc.fieldDesc->extent();
344 switch (fieldType) {
345 case C2FieldDescriptor::INT32:
346 if ((param->second.find(&c2Value) && c2Value.get(&int32Value))
347 || param->second.find(&int32Value)) {
348 work(name, desc, &int32Value, sizeof(int32Value));
349 }
350 break;
351 case C2FieldDescriptor::UINT32:
352 if ((param->second.find(&c2Value) && c2Value.get((uint32_t*)&int32Value))
353 || param->second.find(&int32Value)) {
354 work(name, desc, &int32Value, sizeof(int32Value));
355 }
356 break;
357 case C2FieldDescriptor::CNTR32:
358 if ((param->second.find(&c2Value) && c2Value.get((c2_cntr32_t*)&int32Value))
359 || param->second.find(&int32Value)) {
360 work(name, desc, &int32Value, sizeof(int32Value));
361 }
362 break;
363 case C2FieldDescriptor::INT64:
364 if ((param->second.find(&c2Value) && c2Value.get(&int64Value))
365 || param->second.find(&int64Value)) {
366 work(name, desc, &int64Value, sizeof(int64Value));
367 }
368 break;
369 case C2FieldDescriptor::UINT64:
370 if ((param->second.find(&c2Value) && c2Value.get((uint64_t*)&int64Value))
371 || param->second.find(&int64Value)) {
372 work(name, desc, &int64Value, sizeof(int64Value));
373 }
374 break;
375 case C2FieldDescriptor::CNTR64:
376 if ((param->second.find(&c2Value) && c2Value.get((c2_cntr64_t*)&int64Value))
377 || param->second.find(&int64Value)) {
378 work(name, desc, &int64Value, sizeof(int64Value));
379 }
380 break;
381 case C2FieldDescriptor::FLOAT: {
382 float tmp;
383 if (param->second.find(&c2Value) && c2Value.get(&tmp)) {
384 work(name, desc, &tmp, sizeof(tmp));
385 }
386 break;
387 }
388 case C2FieldDescriptor::STRING: {
389 AString tmp;
390 if (!param->second.find(&tmp)) {
391 break;
392 }
393 if (fieldExtent > 0 && tmp.size() >= fieldExtent) {
394 AString truncated(tmp, 0, fieldExtent - 1);
395 ALOGD("String value too long to fit: original \"%s\" truncated to \"%s\"",
396 tmp.c_str(), truncated.c_str());
397 tmp = truncated;
398 }
399 work(name, desc, tmp.c_str(), tmp.size() + 1);
400 break;
401 }
402
403 case C2FieldDescriptor::BLOB: {
404 sp<ABuffer> tmp;
405 if (!param->second.find(&tmp) || tmp == nullptr) {
406 break;
407 }
408
409 if (fieldExtent > 0 && tmp->size() > fieldExtent) {
410 ALOGD("Blob value too long to fit. Truncating.");
411 tmp->setRange(tmp->offset(), fieldExtent);
412 }
413 work(name, desc, tmp->data(), tmp->size());
414 break;
415 }
416
417 default:
418 ALOGD("Unsupported data type for %s", name.c_str());
419 break;
420 }
421 }
422 }
423
424 ReflectedParamUpdater::Dict
getParams(const std::vector<std::unique_ptr<C2Param>> & params_) const425 ReflectedParamUpdater::getParams(const std::vector<std::unique_ptr<C2Param>> ¶ms_) const {
426 std::vector<C2Param*> params;
427 params.resize(params_.size());
428 std::transform(params_.begin(), params_.end(), params.begin(),
429 [](const std::unique_ptr<C2Param>& p) -> C2Param* { return p.get(); });
430 return getParams(params);
431 }
432
433 ReflectedParamUpdater::Dict
getParams(const std::vector<C2Param * > & params) const434 ReflectedParamUpdater::getParams(const std::vector<C2Param*> ¶ms) const {
435 Dict ret;
436
437 // convert vector to map
438 std::map<C2Param::Index, C2Param *> paramsMap;
439 for (C2Param *param : params) {
440 if (param != nullptr && *param) {
441 paramsMap[param->index()] = param;
442 }
443 }
444
445 for (const std::pair<const std::string, FieldDesc> &kv : mMap) {
446 const std::string &name = kv.first;
447 const FieldDesc &desc = kv.second;
448 if (paramsMap.count(desc.paramDesc->index()) == 0) {
449 continue;
450 }
451 C2Param *param = paramsMap[desc.paramDesc->index()];
452 size_t offset = sizeof(C2Param) + desc.offset
453 + _C2ParamInspector::GetOffset(*desc.fieldDesc);
454 uint8_t *data = (uint8_t *)param + offset;
455 C2FieldDescriptor::type_t fieldType = desc.fieldDesc->type();
456 Value value;
457 switch (fieldType) {
458 case C2FieldDescriptor::STRING: {
459 size_t length = desc.fieldDesc->extent();
460 if (length == 0) {
461 length = param->size() - offset;
462 }
463
464 if (param->size() < length || param->size() - length < offset) {
465 ALOGD("param too small for string: length %zu size %zu offset %zu",
466 length, param->size(), offset);
467 break;
468 }
469 value.set(AString((char *)data, strnlen((char *)data, length)));
470 break;
471 }
472
473 case C2FieldDescriptor::BLOB: {
474 size_t length = desc.fieldDesc->extent();
475 if (length == 0) {
476 length = param->size() - offset;
477 }
478
479 if (param->size() < length || param->size() - length < offset) {
480 ALOGD("param too small for blob: length %zu size %zu offset %zu",
481 length, param->size(), offset);
482 break;
483 }
484
485 sp<ABuffer> buf = ABuffer::CreateAsCopy(data, length);
486 value.set(buf);
487 break;
488 }
489
490 default: {
491 size_t valueSize = C2Value::SizeFor((C2Value::type_t)fieldType);
492 if (param->size() < valueSize || param->size() - valueSize < offset) {
493 ALOGD("param too small for c2value: size %zu offset %zu",
494 param->size(), offset);
495 break;
496 }
497
498 C2Value c2Value;
499 switch (fieldType) {
500 case C2FieldDescriptor::INT32: c2Value = *((int32_t *)data); break;
501 case C2FieldDescriptor::UINT32: c2Value = *((uint32_t *)data); break;
502 case C2FieldDescriptor::CNTR32: c2Value = *((c2_cntr32_t *)data); break;
503 case C2FieldDescriptor::INT64: c2Value = *((int64_t *)data); break;
504 case C2FieldDescriptor::UINT64: c2Value = *((uint64_t *)data); break;
505 case C2FieldDescriptor::CNTR64: c2Value = *((c2_cntr64_t *)data); break;
506 case C2FieldDescriptor::FLOAT: c2Value = *((float *)data); break;
507 default:
508 ALOGD("Unsupported data type for %s", name.c_str());
509 continue;
510 }
511 value.set(c2Value);
512 }
513 }
514 ret.emplace(name, value);
515 }
516 return ret;
517 }
518
clear()519 void ReflectedParamUpdater::clear() {
520 mMap.clear();
521 }
522
523 } // namespace android
524