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