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 = 0;
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 = 0;
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 = 0;
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 = 0;
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 = 0;
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(bool verbose) const319 String8 MetaData::typed_data::asString(bool verbose) 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 (verbose && 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
toString() const370 String8 MetaData::toString() const {
371 String8 s;
372 for (int i = mItems.size(); --i >= 0;) {
373 int32_t key = mItems.keyAt(i);
374 char cc[5];
375 MakeFourCCString(key, cc);
376 const typed_data &item = mItems.valueAt(i);
377 s.appendFormat("%s: %s", cc, item.asString(false).string());
378 if (i != 0) {
379 s.append(", ");
380 }
381 }
382 return s;
383 }
dumpToLog() const384 void MetaData::dumpToLog() const {
385 for (int i = mItems.size(); --i >= 0;) {
386 int32_t key = mItems.keyAt(i);
387 char cc[5];
388 MakeFourCCString(key, cc);
389 const typed_data &item = mItems.valueAt(i);
390 ALOGI("%s: %s", cc, item.asString(true /* verbose */).string());
391 }
392 }
393
writeToParcel(Parcel & parcel)394 status_t MetaData::writeToParcel(Parcel &parcel) {
395 status_t ret;
396 size_t numItems = mItems.size();
397 ret = parcel.writeUint32(uint32_t(numItems));
398 if (ret) {
399 return ret;
400 }
401 for (size_t i = 0; i < numItems; i++) {
402 int32_t key = mItems.keyAt(i);
403 const typed_data &item = mItems.valueAt(i);
404 uint32_t type;
405 const void *data;
406 size_t size;
407 item.getData(&type, &data, &size);
408 ret = parcel.writeInt32(key);
409 if (ret) {
410 return ret;
411 }
412 ret = parcel.writeUint32(type);
413 if (ret) {
414 return ret;
415 }
416 if (type == TYPE_NONE) {
417 android::Parcel::WritableBlob blob;
418 ret = parcel.writeUint32(static_cast<uint32_t>(size));
419 if (ret) {
420 return ret;
421 }
422 ret = parcel.writeBlob(size, false, &blob);
423 if (ret) {
424 return ret;
425 }
426 memcpy(blob.data(), data, size);
427 blob.release();
428 } else {
429 ret = parcel.writeByteArray(size, (uint8_t*)data);
430 if (ret) {
431 return ret;
432 }
433 }
434 }
435 return OK;
436 }
437
updateFromParcel(const Parcel & parcel)438 status_t MetaData::updateFromParcel(const Parcel &parcel) {
439 uint32_t numItems;
440 if (parcel.readUint32(&numItems) == OK) {
441
442 for (size_t i = 0; i < numItems; i++) {
443 int32_t key;
444 uint32_t type;
445 uint32_t size;
446 status_t ret = parcel.readInt32(&key);
447 ret |= parcel.readUint32(&type);
448 ret |= parcel.readUint32(&size);
449 if (ret != OK) {
450 break;
451 }
452 // copy data from Blob, which may be inline in Parcel storage,
453 // then advance position
454 if (type == TYPE_NONE) {
455 android::Parcel::ReadableBlob blob;
456 ret = parcel.readBlob(size, &blob);
457 if (ret != OK) {
458 break;
459 }
460 setData(key, type, blob.data(), size);
461 blob.release();
462 } else {
463 // copy data directly from Parcel storage, then advance position
464 setData(key, type, parcel.readInplace(size), size);
465 }
466 }
467
468 return OK;
469 }
470 ALOGW("no metadata in parcel");
471 return UNKNOWN_ERROR;
472 }
473
474
475 /* static */
createFromParcel(const Parcel & parcel)476 sp<MetaData> MetaData::createFromParcel(const Parcel &parcel) {
477
478 sp<MetaData> meta = new MetaData();
479 meta->updateFromParcel(parcel);
480 return meta;
481 }
482
483
484
485 } // namespace android
486
487