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