• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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