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