Home | History | Annotate | Download | only in libmediaextractor
      1 /*
      2  * Copyright (C) 2009 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 "MetaDataBase"
     19 #include <inttypes.h>
     20 #include <binder/Parcel.h>
     21 #include <utils/KeyedVector.h>
     22 #include <utils/Log.h>
     23 
     24 #include <stdlib.h>
     25 #include <string.h>
     26 
     27 #include <media/stagefright/foundation/ADebug.h>
     28 #include <media/stagefright/foundation/AString.h>
     29 #include <media/stagefright/foundation/hexdump.h>
     30 #include <media/stagefright/MetaDataBase.h>
     31 
     32 namespace android {
     33 
     34 struct MetaDataBase::typed_data {
     35     typed_data();
     36     ~typed_data();
     37 
     38     typed_data(const MetaDataBase::typed_data &);
     39     typed_data &operator=(const MetaDataBase::typed_data &);
     40 
     41     void clear();
     42     void setData(uint32_t type, const void *data, size_t size);
     43     void getData(uint32_t *type, const void **data, size_t *size) const;
     44     // may include hexdump of binary data if verbose=true
     45     String8 asString(bool verbose) const;
     46 
     47 private:
     48     uint32_t mType;
     49     size_t mSize;
     50 
     51     union {
     52         void *ext_data;
     53         float reservoir;
     54     } u;
     55 
     56     bool usesReservoir() const {
     57         return mSize <= sizeof(u.reservoir);
     58     }
     59 
     60     void *allocateStorage(size_t size);
     61     void freeStorage();
     62 
     63     void *storage() {
     64         return usesReservoir() ? &u.reservoir : u.ext_data;
     65     }
     66 
     67     const void *storage() const {
     68         return usesReservoir() ? &u.reservoir : u.ext_data;
     69     }
     70 };
     71 
     72 struct MetaDataBase::Rect {
     73     int32_t mLeft, mTop, mRight, mBottom;
     74 };
     75 
     76 
     77 struct MetaDataBase::MetaDataInternal {
     78     KeyedVector<uint32_t, MetaDataBase::typed_data> mItems;
     79 };
     80 
     81 
     82 MetaDataBase::MetaDataBase()
     83     : mInternalData(new MetaDataInternal()) {
     84 }
     85 
     86 MetaDataBase::MetaDataBase(const MetaDataBase &from)
     87     : mInternalData(new MetaDataInternal()) {
     88     mInternalData->mItems = from.mInternalData->mItems;
     89 }
     90 
     91 MetaDataBase& MetaDataBase::operator = (const MetaDataBase &rhs) {
     92     this->mInternalData->mItems = rhs.mInternalData->mItems;
     93     return *this;
     94 }
     95 
     96 MetaDataBase::~MetaDataBase() {
     97     clear();
     98     delete mInternalData;
     99 }
    100 
    101 void MetaDataBase::clear() {
    102     mInternalData->mItems.clear();
    103 }
    104 
    105 bool MetaDataBase::remove(uint32_t key) {
    106     ssize_t i = mInternalData->mItems.indexOfKey(key);
    107 
    108     if (i < 0) {
    109         return false;
    110     }
    111 
    112     mInternalData->mItems.removeItemsAt(i);
    113 
    114     return true;
    115 }
    116 
    117 bool MetaDataBase::setCString(uint32_t key, const char *value) {
    118     return setData(key, TYPE_C_STRING, value, strlen(value) + 1);
    119 }
    120 
    121 bool MetaDataBase::setInt32(uint32_t key, int32_t value) {
    122     return setData(key, TYPE_INT32, &value, sizeof(value));
    123 }
    124 
    125 bool MetaDataBase::setInt64(uint32_t key, int64_t value) {
    126     return setData(key, TYPE_INT64, &value, sizeof(value));
    127 }
    128 
    129 bool MetaDataBase::setFloat(uint32_t key, float value) {
    130     return setData(key, TYPE_FLOAT, &value, sizeof(value));
    131 }
    132 
    133 bool MetaDataBase::setPointer(uint32_t key, void *value) {
    134     return setData(key, TYPE_POINTER, &value, sizeof(value));
    135 }
    136 
    137 bool MetaDataBase::setRect(
    138         uint32_t key,
    139         int32_t left, int32_t top,
    140         int32_t right, int32_t bottom) {
    141     Rect r;
    142     r.mLeft = left;
    143     r.mTop = top;
    144     r.mRight = right;
    145     r.mBottom = bottom;
    146 
    147     return setData(key, TYPE_RECT, &r, sizeof(r));
    148 }
    149 
    150 /**
    151  * Note that the returned pointer becomes invalid when additional metadata is set.
    152  */
    153 bool MetaDataBase::findCString(uint32_t key, const char **value) const {
    154     uint32_t type;
    155     const void *data;
    156     size_t size;
    157     if (!findData(key, &type, &data, &size) || type != TYPE_C_STRING) {
    158         return false;
    159     }
    160 
    161     *value = (const char *)data;
    162 
    163     return true;
    164 }
    165 
    166 bool MetaDataBase::findInt32(uint32_t key, int32_t *value) const {
    167     uint32_t type = 0;
    168     const void *data;
    169     size_t size;
    170     if (!findData(key, &type, &data, &size) || type != TYPE_INT32) {
    171         return false;
    172     }
    173 
    174     CHECK_EQ(size, sizeof(*value));
    175 
    176     *value = *(int32_t *)data;
    177 
    178     return true;
    179 }
    180 
    181 bool MetaDataBase::findInt64(uint32_t key, int64_t *value) const {
    182     uint32_t type = 0;
    183     const void *data;
    184     size_t size;
    185     if (!findData(key, &type, &data, &size) || type != TYPE_INT64) {
    186         return false;
    187     }
    188 
    189     CHECK_EQ(size, sizeof(*value));
    190 
    191     *value = *(int64_t *)data;
    192 
    193     return true;
    194 }
    195 
    196 bool MetaDataBase::findFloat(uint32_t key, float *value) const {
    197     uint32_t type = 0;
    198     const void *data;
    199     size_t size;
    200     if (!findData(key, &type, &data, &size) || type != TYPE_FLOAT) {
    201         return false;
    202     }
    203 
    204     CHECK_EQ(size, sizeof(*value));
    205 
    206     *value = *(float *)data;
    207 
    208     return true;
    209 }
    210 
    211 bool MetaDataBase::findPointer(uint32_t key, void **value) const {
    212     uint32_t type = 0;
    213     const void *data;
    214     size_t size;
    215     if (!findData(key, &type, &data, &size) || type != TYPE_POINTER) {
    216         return false;
    217     }
    218 
    219     CHECK_EQ(size, sizeof(*value));
    220 
    221     *value = *(void **)data;
    222 
    223     return true;
    224 }
    225 
    226 bool MetaDataBase::findRect(
    227         uint32_t key,
    228         int32_t *left, int32_t *top,
    229         int32_t *right, int32_t *bottom) const {
    230     uint32_t type = 0;
    231     const void *data;
    232     size_t size;
    233     if (!findData(key, &type, &data, &size) || type != TYPE_RECT) {
    234         return false;
    235     }
    236 
    237     CHECK_EQ(size, sizeof(Rect));
    238 
    239     const Rect *r = (const Rect *)data;
    240     *left = r->mLeft;
    241     *top = r->mTop;
    242     *right = r->mRight;
    243     *bottom = r->mBottom;
    244 
    245     return true;
    246 }
    247 
    248 bool MetaDataBase::setData(
    249         uint32_t key, uint32_t type, const void *data, size_t size) {
    250     bool overwrote_existing = true;
    251 
    252     ssize_t i = mInternalData->mItems.indexOfKey(key);
    253     if (i < 0) {
    254         typed_data item;
    255         i = mInternalData->mItems.add(key, item);
    256 
    257         overwrote_existing = false;
    258     }
    259 
    260     typed_data &item = mInternalData->mItems.editValueAt(i);
    261 
    262     item.setData(type, data, size);
    263 
    264     return overwrote_existing;
    265 }
    266 
    267 bool MetaDataBase::findData(uint32_t key, uint32_t *type,
    268                         const void **data, size_t *size) const {
    269     ssize_t i = mInternalData->mItems.indexOfKey(key);
    270 
    271     if (i < 0) {
    272         return false;
    273     }
    274 
    275     const typed_data &item = mInternalData->mItems.valueAt(i);
    276 
    277     item.getData(type, data, size);
    278 
    279     return true;
    280 }
    281 
    282 bool MetaDataBase::hasData(uint32_t key) const {
    283     ssize_t i = mInternalData->mItems.indexOfKey(key);
    284 
    285     if (i < 0) {
    286         return false;
    287     }
    288 
    289     return true;
    290 }
    291 
    292 MetaDataBase::typed_data::typed_data()
    293     : mType(0),
    294       mSize(0) {
    295 }
    296 
    297 MetaDataBase::typed_data::~typed_data() {
    298     clear();
    299 }
    300 
    301 MetaDataBase::typed_data::typed_data(const typed_data &from)
    302     : mType(from.mType),
    303       mSize(0) {
    304 
    305     void *dst = allocateStorage(from.mSize);
    306     if (dst) {
    307         memcpy(dst, from.storage(), mSize);
    308     }
    309 }
    310 
    311 MetaDataBase::typed_data &MetaDataBase::typed_data::operator=(
    312         const MetaDataBase::typed_data &from) {
    313     if (this != &from) {
    314         clear();
    315         mType = from.mType;
    316         void *dst = allocateStorage(from.mSize);
    317         if (dst) {
    318             memcpy(dst, from.storage(), mSize);
    319         }
    320     }
    321 
    322     return *this;
    323 }
    324 
    325 void MetaDataBase::typed_data::clear() {
    326     freeStorage();
    327 
    328     mType = 0;
    329 }
    330 
    331 void MetaDataBase::typed_data::setData(
    332         uint32_t type, const void *data, size_t size) {
    333     clear();
    334 
    335     mType = type;
    336 
    337     void *dst = allocateStorage(size);
    338     if (dst) {
    339         memcpy(dst, data, size);
    340     }
    341 }
    342 
    343 void MetaDataBase::typed_data::getData(
    344         uint32_t *type, const void **data, size_t *size) const {
    345     *type = mType;
    346     *size = mSize;
    347     *data = storage();
    348 }
    349 
    350 void *MetaDataBase::typed_data::allocateStorage(size_t size) {
    351     mSize = size;
    352 
    353     if (usesReservoir()) {
    354         return &u.reservoir;
    355     }
    356 
    357     u.ext_data = malloc(mSize);
    358     if (u.ext_data == NULL) {
    359         ALOGE("Couldn't allocate %zu bytes for item", size);
    360         mSize = 0;
    361     }
    362     return u.ext_data;
    363 }
    364 
    365 void MetaDataBase::typed_data::freeStorage() {
    366     if (!usesReservoir()) {
    367         if (u.ext_data) {
    368             free(u.ext_data);
    369             u.ext_data = NULL;
    370         }
    371     }
    372 
    373     mSize = 0;
    374 }
    375 
    376 String8 MetaDataBase::typed_data::asString(bool verbose) const {
    377     String8 out;
    378     const void *data = storage();
    379     switch(mType) {
    380         case TYPE_NONE:
    381             out = String8::format("no type, size %zu)", mSize);
    382             break;
    383         case TYPE_C_STRING:
    384             out = String8::format("(char*) %s", (const char *)data);
    385             break;
    386         case TYPE_INT32:
    387             out = String8::format("(int32_t) %d", *(int32_t *)data);
    388             break;
    389         case TYPE_INT64:
    390             out = String8::format("(int64_t) %" PRId64, *(int64_t *)data);
    391             break;
    392         case TYPE_FLOAT:
    393             out = String8::format("(float) %f", *(float *)data);
    394             break;
    395         case TYPE_POINTER:
    396             out = String8::format("(void*) %p", *(void **)data);
    397             break;
    398         case TYPE_RECT:
    399         {
    400             const Rect *r = (const Rect *)data;
    401             out = String8::format("Rect(%d, %d, %d, %d)",
    402                                   r->mLeft, r->mTop, r->mRight, r->mBottom);
    403             break;
    404         }
    405 
    406         default:
    407             out = String8::format("(unknown type %d, size %zu)", mType, mSize);
    408             if (verbose && mSize <= 48) { // if it's less than three lines of hex data, dump it
    409                 AString foo;
    410                 hexdump(data, mSize, 0, &foo);
    411                 out.append("\n");
    412                 out.append(foo.c_str());
    413             }
    414             break;
    415     }
    416     return out;
    417 }
    418 
    419 static void MakeFourCCString(uint32_t x, char *s) {
    420     s[0] = x >> 24;
    421     s[1] = (x >> 16) & 0xff;
    422     s[2] = (x >> 8) & 0xff;
    423     s[3] = x & 0xff;
    424     s[4] = '\0';
    425 }
    426 
    427 String8 MetaDataBase::toString() const {
    428     String8 s;
    429     for (int i = mInternalData->mItems.size(); --i >= 0;) {
    430         int32_t key = mInternalData->mItems.keyAt(i);
    431         char cc[5];
    432         MakeFourCCString(key, cc);
    433         const typed_data &item = mInternalData->mItems.valueAt(i);
    434         s.appendFormat("%s: %s", cc, item.asString(false).string());
    435         if (i != 0) {
    436             s.append(", ");
    437         }
    438     }
    439     return s;
    440 }
    441 
    442 void MetaDataBase::dumpToLog() const {
    443     for (int i = mInternalData->mItems.size(); --i >= 0;) {
    444         int32_t key = mInternalData->mItems.keyAt(i);
    445         char cc[5];
    446         MakeFourCCString(key, cc);
    447         const typed_data &item = mInternalData->mItems.valueAt(i);
    448         ALOGI("%s: %s", cc, item.asString(true /* verbose */).string());
    449     }
    450 }
    451 
    452 status_t MetaDataBase::writeToParcel(Parcel &parcel) {
    453     status_t ret;
    454     size_t numItems = mInternalData->mItems.size();
    455     ret = parcel.writeUint32(uint32_t(numItems));
    456     if (ret) {
    457         return ret;
    458     }
    459     for (size_t i = 0; i < numItems; i++) {
    460         int32_t key = mInternalData->mItems.keyAt(i);
    461         const typed_data &item = mInternalData->mItems.valueAt(i);
    462         uint32_t type;
    463         const void *data;
    464         size_t size;
    465         item.getData(&type, &data, &size);
    466         ret = parcel.writeInt32(key);
    467         if (ret) {
    468             return ret;
    469         }
    470         ret = parcel.writeUint32(type);
    471         if (ret) {
    472             return ret;
    473         }
    474         if (type == TYPE_NONE) {
    475             android::Parcel::WritableBlob blob;
    476             ret = parcel.writeUint32(static_cast<uint32_t>(size));
    477             if (ret) {
    478                 return ret;
    479             }
    480             ret = parcel.writeBlob(size, false, &blob);
    481             if (ret) {
    482                 return ret;
    483             }
    484             memcpy(blob.data(), data, size);
    485             blob.release();
    486         } else {
    487             ret = parcel.writeByteArray(size, (uint8_t*)data);
    488             if (ret) {
    489                 return ret;
    490             }
    491         }
    492     }
    493     return OK;
    494 }
    495 
    496 status_t MetaDataBase::updateFromParcel(const Parcel &parcel) {
    497     uint32_t numItems;
    498     if (parcel.readUint32(&numItems) == OK) {
    499 
    500         for (size_t i = 0; i < numItems; i++) {
    501             int32_t key;
    502             uint32_t type;
    503             uint32_t size;
    504             status_t ret = parcel.readInt32(&key);
    505             ret |= parcel.readUint32(&type);
    506             ret |= parcel.readUint32(&size);
    507             if (ret != OK) {
    508                 break;
    509             }
    510             // copy data from Blob, which may be inline in Parcel storage,
    511             // then advance position
    512             if (type == TYPE_NONE) {
    513                 android::Parcel::ReadableBlob blob;
    514                 ret = parcel.readBlob(size, &blob);
    515                 if (ret != OK) {
    516                     break;
    517                 }
    518                 setData(key, type, blob.data(), size);
    519                 blob.release();
    520             } else {
    521                 // copy data directly from Parcel storage, then advance position
    522                 setData(key, type, parcel.readInplace(size), size);
    523             }
    524          }
    525 
    526         return OK;
    527     }
    528     ALOGW("no metadata in parcel");
    529     return UNKNOWN_ERROR;
    530 }
    531 
    532 }  // namespace android
    533 
    534