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 "MetaData"
19 #include <inttypes.h>
20 #include <utils/Log.h>
21 
22 #include <stdlib.h>
23 #include <string.h>
24 
25 #include <media/stagefright/foundation/ADebug.h>
26 #include <media/stagefright/foundation/AString.h>
27 #include <media/stagefright/foundation/hexdump.h>
28 #include <media/stagefright/MetaData.h>
29 
30 namespace android {
31 
MetaData()32 MetaData::MetaData() {
33 }
34 
MetaData(const MetaData & from)35 MetaData::MetaData(const MetaData &from)
36     : RefBase(),
37       mItems(from.mItems) {
38 }
39 
~MetaData()40 MetaData::~MetaData() {
41     clear();
42 }
43 
clear()44 void MetaData::clear() {
45     mItems.clear();
46 }
47 
remove(uint32_t key)48 bool MetaData::remove(uint32_t key) {
49     ssize_t i = mItems.indexOfKey(key);
50 
51     if (i < 0) {
52         return false;
53     }
54 
55     mItems.removeItemsAt(i);
56 
57     return true;
58 }
59 
setCString(uint32_t key,const char * value)60 bool MetaData::setCString(uint32_t key, const char *value) {
61     return setData(key, TYPE_C_STRING, value, strlen(value) + 1);
62 }
63 
setInt32(uint32_t key,int32_t value)64 bool MetaData::setInt32(uint32_t key, int32_t value) {
65     return setData(key, TYPE_INT32, &value, sizeof(value));
66 }
67 
setInt64(uint32_t key,int64_t value)68 bool MetaData::setInt64(uint32_t key, int64_t value) {
69     return setData(key, TYPE_INT64, &value, sizeof(value));
70 }
71 
setFloat(uint32_t key,float value)72 bool MetaData::setFloat(uint32_t key, float value) {
73     return setData(key, TYPE_FLOAT, &value, sizeof(value));
74 }
75 
setPointer(uint32_t key,void * value)76 bool MetaData::setPointer(uint32_t key, void *value) {
77     return setData(key, TYPE_POINTER, &value, sizeof(value));
78 }
79 
setRect(uint32_t key,int32_t left,int32_t top,int32_t right,int32_t bottom)80 bool MetaData::setRect(
81         uint32_t key,
82         int32_t left, int32_t top,
83         int32_t right, int32_t bottom) {
84     Rect r;
85     r.mLeft = left;
86     r.mTop = top;
87     r.mRight = right;
88     r.mBottom = bottom;
89 
90     return setData(key, TYPE_RECT, &r, sizeof(r));
91 }
92 
93 /**
94  * Note that the returned pointer becomes invalid when additional metadata is set.
95  */
findCString(uint32_t key,const char ** value)96 bool MetaData::findCString(uint32_t key, const char **value) {
97     uint32_t type;
98     const void *data;
99     size_t size;
100     if (!findData(key, &type, &data, &size) || type != TYPE_C_STRING) {
101         return false;
102     }
103 
104     *value = (const char *)data;
105 
106     return true;
107 }
108 
findInt32(uint32_t key,int32_t * value)109 bool MetaData::findInt32(uint32_t key, int32_t *value) {
110     uint32_t type;
111     const void *data;
112     size_t size;
113     if (!findData(key, &type, &data, &size) || type != TYPE_INT32) {
114         return false;
115     }
116 
117     CHECK_EQ(size, sizeof(*value));
118 
119     *value = *(int32_t *)data;
120 
121     return true;
122 }
123 
findInt64(uint32_t key,int64_t * value)124 bool MetaData::findInt64(uint32_t key, int64_t *value) {
125     uint32_t type;
126     const void *data;
127     size_t size;
128     if (!findData(key, &type, &data, &size) || type != TYPE_INT64) {
129         return false;
130     }
131 
132     CHECK_EQ(size, sizeof(*value));
133 
134     *value = *(int64_t *)data;
135 
136     return true;
137 }
138 
findFloat(uint32_t key,float * value)139 bool MetaData::findFloat(uint32_t key, float *value) {
140     uint32_t type;
141     const void *data;
142     size_t size;
143     if (!findData(key, &type, &data, &size) || type != TYPE_FLOAT) {
144         return false;
145     }
146 
147     CHECK_EQ(size, sizeof(*value));
148 
149     *value = *(float *)data;
150 
151     return true;
152 }
153 
findPointer(uint32_t key,void ** value)154 bool MetaData::findPointer(uint32_t key, void **value) {
155     uint32_t type;
156     const void *data;
157     size_t size;
158     if (!findData(key, &type, &data, &size) || type != TYPE_POINTER) {
159         return false;
160     }
161 
162     CHECK_EQ(size, sizeof(*value));
163 
164     *value = *(void **)data;
165 
166     return true;
167 }
168 
findRect(uint32_t key,int32_t * left,int32_t * top,int32_t * right,int32_t * bottom)169 bool MetaData::findRect(
170         uint32_t key,
171         int32_t *left, int32_t *top,
172         int32_t *right, int32_t *bottom) {
173     uint32_t type;
174     const void *data;
175     size_t size;
176     if (!findData(key, &type, &data, &size) || type != TYPE_RECT) {
177         return false;
178     }
179 
180     CHECK_EQ(size, sizeof(Rect));
181 
182     const Rect *r = (const Rect *)data;
183     *left = r->mLeft;
184     *top = r->mTop;
185     *right = r->mRight;
186     *bottom = r->mBottom;
187 
188     return true;
189 }
190 
setData(uint32_t key,uint32_t type,const void * data,size_t size)191 bool MetaData::setData(
192         uint32_t key, uint32_t type, const void *data, size_t size) {
193     bool overwrote_existing = true;
194 
195     ssize_t i = mItems.indexOfKey(key);
196     if (i < 0) {
197         typed_data item;
198         i = mItems.add(key, item);
199 
200         overwrote_existing = false;
201     }
202 
203     typed_data &item = mItems.editValueAt(i);
204 
205     item.setData(type, data, size);
206 
207     return overwrote_existing;
208 }
209 
findData(uint32_t key,uint32_t * type,const void ** data,size_t * size) const210 bool MetaData::findData(uint32_t key, uint32_t *type,
211                         const void **data, size_t *size) const {
212     ssize_t i = mItems.indexOfKey(key);
213 
214     if (i < 0) {
215         return false;
216     }
217 
218     const typed_data &item = mItems.valueAt(i);
219 
220     item.getData(type, data, size);
221 
222     return true;
223 }
224 
hasData(uint32_t key) const225 bool MetaData::hasData(uint32_t key) const {
226     ssize_t i = mItems.indexOfKey(key);
227 
228     if (i < 0) {
229         return false;
230     }
231 
232     return true;
233 }
234 
typed_data()235 MetaData::typed_data::typed_data()
236     : mType(0),
237       mSize(0) {
238 }
239 
~typed_data()240 MetaData::typed_data::~typed_data() {
241     clear();
242 }
243 
typed_data(const typed_data & from)244 MetaData::typed_data::typed_data(const typed_data &from)
245     : mType(from.mType),
246       mSize(0) {
247 
248     void *dst = allocateStorage(from.mSize);
249     if (dst) {
250         memcpy(dst, from.storage(), mSize);
251     }
252 }
253 
operator =(const MetaData::typed_data & from)254 MetaData::typed_data &MetaData::typed_data::operator=(
255         const MetaData::typed_data &from) {
256     if (this != &from) {
257         clear();
258         mType = from.mType;
259         void *dst = allocateStorage(from.mSize);
260         if (dst) {
261             memcpy(dst, from.storage(), mSize);
262         }
263     }
264 
265     return *this;
266 }
267 
clear()268 void MetaData::typed_data::clear() {
269     freeStorage();
270 
271     mType = 0;
272 }
273 
setData(uint32_t type,const void * data,size_t size)274 void MetaData::typed_data::setData(
275         uint32_t type, const void *data, size_t size) {
276     clear();
277 
278     mType = type;
279 
280     void *dst = allocateStorage(size);
281     if (dst) {
282         memcpy(dst, data, size);
283     }
284 }
285 
getData(uint32_t * type,const void ** data,size_t * size) const286 void MetaData::typed_data::getData(
287         uint32_t *type, const void **data, size_t *size) const {
288     *type = mType;
289     *size = mSize;
290     *data = storage();
291 }
292 
allocateStorage(size_t size)293 void *MetaData::typed_data::allocateStorage(size_t size) {
294     mSize = size;
295 
296     if (usesReservoir()) {
297         return &u.reservoir;
298     }
299 
300     u.ext_data = malloc(mSize);
301     if (u.ext_data == NULL) {
302         ALOGE("Couldn't allocate %zu bytes for item", size);
303         mSize = 0;
304     }
305     return u.ext_data;
306 }
307 
freeStorage()308 void MetaData::typed_data::freeStorage() {
309     if (!usesReservoir()) {
310         if (u.ext_data) {
311             free(u.ext_data);
312             u.ext_data = NULL;
313         }
314     }
315 
316     mSize = 0;
317 }
318 
asString() const319 String8 MetaData::typed_data::asString() const {
320     String8 out;
321     const void *data = storage();
322     switch(mType) {
323         case TYPE_NONE:
324             out = String8::format("no type, size %zu)", mSize);
325             break;
326         case TYPE_C_STRING:
327             out = String8::format("(char*) %s", (const char *)data);
328             break;
329         case TYPE_INT32:
330             out = String8::format("(int32_t) %d", *(int32_t *)data);
331             break;
332         case TYPE_INT64:
333             out = String8::format("(int64_t) %" PRId64, *(int64_t *)data);
334             break;
335         case TYPE_FLOAT:
336             out = String8::format("(float) %f", *(float *)data);
337             break;
338         case TYPE_POINTER:
339             out = String8::format("(void*) %p", *(void **)data);
340             break;
341         case TYPE_RECT:
342         {
343             const Rect *r = (const Rect *)data;
344             out = String8::format("Rect(%d, %d, %d, %d)",
345                                   r->mLeft, r->mTop, r->mRight, r->mBottom);
346             break;
347         }
348 
349         default:
350             out = String8::format("(unknown type %d, size %zu)", mType, mSize);
351             if (mSize <= 48) { // if it's less than three lines of hex data, dump it
352                 AString foo;
353                 hexdump(data, mSize, 0, &foo);
354                 out.append("\n");
355                 out.append(foo.c_str());
356             }
357             break;
358     }
359     return out;
360 }
361 
MakeFourCCString(uint32_t x,char * s)362 static void MakeFourCCString(uint32_t x, char *s) {
363     s[0] = x >> 24;
364     s[1] = (x >> 16) & 0xff;
365     s[2] = (x >> 8) & 0xff;
366     s[3] = x & 0xff;
367     s[4] = '\0';
368 }
369 
dumpToLog() const370 void MetaData::dumpToLog() const {
371     for (int i = mItems.size(); --i >= 0;) {
372         int32_t key = mItems.keyAt(i);
373         char cc[5];
374         MakeFourCCString(key, cc);
375         const typed_data &item = mItems.valueAt(i);
376         ALOGI("%s: %s", cc, item.asString().string());
377     }
378 }
379 
380 }  // namespace android
381 
382