Home | History | Annotate | Download | only in sfplugin
      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>> &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 
    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 &params,
    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 &params,
    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> &param : *vec) {
    296         if (param && *param) {
    297             paramsMap[param->index()] = &param;
    298         }
    299     }
    300 
    301     parseMessageAndDoWork(
    302             params,
    303             [&paramsMap](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 &params,
    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>> &params_) 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*> &params) 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