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