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