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