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
usesReservoirandroid::MetaDataBase::typed_data56 bool usesReservoir() const {
57 return mSize <= sizeof(u.reservoir);
58 }
59
60 void *allocateStorage(size_t size);
61 void freeStorage();
62
storageandroid::MetaDataBase::typed_data63 void *storage() {
64 return usesReservoir() ? &u.reservoir : u.ext_data;
65 }
66
storageandroid::MetaDataBase::typed_data67 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
MetaDataBase()82 MetaDataBase::MetaDataBase()
83 : mInternalData(new MetaDataInternal()) {
84 }
85
MetaDataBase(const MetaDataBase & from)86 MetaDataBase::MetaDataBase(const MetaDataBase &from)
87 : mInternalData(new MetaDataInternal()) {
88 mInternalData->mItems = from.mInternalData->mItems;
89 }
90
operator =(const MetaDataBase & rhs)91 MetaDataBase& MetaDataBase::operator = (const MetaDataBase &rhs) {
92 this->mInternalData->mItems = rhs.mInternalData->mItems;
93 return *this;
94 }
95
~MetaDataBase()96 MetaDataBase::~MetaDataBase() {
97 clear();
98 delete mInternalData;
99 }
100
clear()101 void MetaDataBase::clear() {
102 mInternalData->mItems.clear();
103 }
104
remove(uint32_t key)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
setCString(uint32_t key,const char * value)117 bool MetaDataBase::setCString(uint32_t key, const char *value) {
118 return setData(key, TYPE_C_STRING, value, strlen(value) + 1);
119 }
120
setInt32(uint32_t key,int32_t value)121 bool MetaDataBase::setInt32(uint32_t key, int32_t value) {
122 return setData(key, TYPE_INT32, &value, sizeof(value));
123 }
124
setInt64(uint32_t key,int64_t value)125 bool MetaDataBase::setInt64(uint32_t key, int64_t value) {
126 return setData(key, TYPE_INT64, &value, sizeof(value));
127 }
128
setFloat(uint32_t key,float value)129 bool MetaDataBase::setFloat(uint32_t key, float value) {
130 return setData(key, TYPE_FLOAT, &value, sizeof(value));
131 }
132
setPointer(uint32_t key,void * value)133 bool MetaDataBase::setPointer(uint32_t key, void *value) {
134 return setData(key, TYPE_POINTER, &value, sizeof(value));
135 }
136
setRect(uint32_t key,int32_t left,int32_t top,int32_t right,int32_t bottom)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 */
findCString(uint32_t key,const char ** value) const153 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
findInt32(uint32_t key,int32_t * value) const166 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
findInt64(uint32_t key,int64_t * value) const181 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
findFloat(uint32_t key,float * value) const196 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
findPointer(uint32_t key,void ** value) const211 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
findRect(uint32_t key,int32_t * left,int32_t * top,int32_t * right,int32_t * bottom) const226 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
setData(uint32_t key,uint32_t type,const void * data,size_t size)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
findData(uint32_t key,uint32_t * type,const void ** data,size_t * size) const267 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
hasData(uint32_t key) const282 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
typed_data()292 MetaDataBase::typed_data::typed_data()
293 : mType(0),
294 mSize(0) {
295 }
296
~typed_data()297 MetaDataBase::typed_data::~typed_data() {
298 clear();
299 }
300
typed_data(const typed_data & from)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
operator =(const MetaDataBase::typed_data & from)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
clear()325 void MetaDataBase::typed_data::clear() {
326 freeStorage();
327
328 mType = 0;
329 }
330
setData(uint32_t type,const void * data,size_t size)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
getData(uint32_t * type,const void ** data,size_t * size) const343 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
allocateStorage(size_t size)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
freeStorage()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
asString(bool verbose) const376 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
MakeFourCCString(uint32_t x,char * s)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
toString() const427 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
dumpToLog() const442 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
writeToParcel(Parcel & parcel)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
updateFromParcel(const Parcel & parcel)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