blob: 69beea10b29fbe46f953ed7af6ef577eee462390 [file] [log] [blame]
Andreas Huber20111aa2009-07-14 16:56:47 -07001/*
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
Marco Nelissenfeba11f2012-03-21 12:27:00 -070017//#define LOG_NDEBUG 0
18#define LOG_TAG "MetaData"
Kévin PETIT377b2ec2014-02-03 12:35:36 +000019#include <inttypes.h>
Dongwon Kang84415e02018-01-26 15:10:06 -080020#include <binder/Parcel.h>
Marco Nelissen389f0fe2018-01-23 11:22:14 -080021#include <utils/KeyedVector.h>
Marco Nelissenfeba11f2012-03-21 12:27:00 -070022#include <utils/Log.h>
23
Andreas Huber20111aa2009-07-14 16:56:47 -070024#include <stdlib.h>
25#include <string.h>
26
James Dongf1d5aa12012-02-06 23:46:37 -080027#include <media/stagefright/foundation/ADebug.h>
Marco Nelissen56997122012-08-28 15:09:49 -070028#include <media/stagefright/foundation/AString.h>
29#include <media/stagefright/foundation/hexdump.h>
Andreas Huber20111aa2009-07-14 16:56:47 -070030#include <media/stagefright/MetaData.h>
31
32namespace android {
33
Marco Nelissen389f0fe2018-01-23 11:22:14 -080034struct MetaData::typed_data {
35 typed_data();
36 ~typed_data();
37
38 typed_data(const MetaData::typed_data &);
39 typed_data &operator=(const MetaData::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
47private:
48 uint32_t mType;
49 size_t mSize;
50
51 union {
52 void *ext_data;
53 float reservoir;
54 } u;
55
56 bool usesReservoir() const {
57 return mSize <= sizeof(u.reservoir);
58 }
59
60 void *allocateStorage(size_t size);
61 void freeStorage();
62
63 void *storage() {
64 return usesReservoir() ? &u.reservoir : u.ext_data;
65 }
66
67 const void *storage() const {
68 return usesReservoir() ? &u.reservoir : u.ext_data;
69 }
70};
71
72struct MetaData::Rect {
73 int32_t mLeft, mTop, mRight, mBottom;
74};
75
76
77struct MetaData::MetaDataInternal {
78 KeyedVector<uint32_t, MetaData::typed_data> mItems;
79};
80
81
82MetaData::MetaData()
83 : mInternalData(new MetaDataInternal()) {
Andreas Huber20111aa2009-07-14 16:56:47 -070084}
85
86MetaData::MetaData(const MetaData &from)
87 : RefBase(),
Marco Nelissen389f0fe2018-01-23 11:22:14 -080088 mInternalData(new MetaDataInternal()) {
89 mInternalData->mItems = from.mInternalData->mItems;
Andreas Huber20111aa2009-07-14 16:56:47 -070090}
91
92MetaData::~MetaData() {
93 clear();
Marco Nelissen389f0fe2018-01-23 11:22:14 -080094 delete mInternalData;
Andreas Huber20111aa2009-07-14 16:56:47 -070095}
96
97void MetaData::clear() {
Marco Nelissen389f0fe2018-01-23 11:22:14 -080098 mInternalData->mItems.clear();
Andreas Huber20111aa2009-07-14 16:56:47 -070099}
100
101bool MetaData::remove(uint32_t key) {
Marco Nelissen389f0fe2018-01-23 11:22:14 -0800102 ssize_t i = mInternalData->mItems.indexOfKey(key);
Andreas Huber20111aa2009-07-14 16:56:47 -0700103
104 if (i < 0) {
105 return false;
106 }
107
Marco Nelissen389f0fe2018-01-23 11:22:14 -0800108 mInternalData->mItems.removeItemsAt(i);
Andreas Huber20111aa2009-07-14 16:56:47 -0700109
110 return true;
111}
112
113bool MetaData::setCString(uint32_t key, const char *value) {
114 return setData(key, TYPE_C_STRING, value, strlen(value) + 1);
115}
116
117bool MetaData::setInt32(uint32_t key, int32_t value) {
118 return setData(key, TYPE_INT32, &value, sizeof(value));
119}
120
Andreas Huber48c948b2009-10-08 10:07:49 -0700121bool MetaData::setInt64(uint32_t key, int64_t value) {
122 return setData(key, TYPE_INT64, &value, sizeof(value));
123}
124
Andreas Huber20111aa2009-07-14 16:56:47 -0700125bool MetaData::setFloat(uint32_t key, float value) {
126 return setData(key, TYPE_FLOAT, &value, sizeof(value));
127}
128
129bool MetaData::setPointer(uint32_t key, void *value) {
130 return setData(key, TYPE_POINTER, &value, sizeof(value));
131}
132
Andreas Huberf5ab57c2010-11-22 13:06:35 -0800133bool MetaData::setRect(
134 uint32_t key,
135 int32_t left, int32_t top,
136 int32_t right, int32_t bottom) {
137 Rect r;
138 r.mLeft = left;
139 r.mTop = top;
140 r.mRight = right;
141 r.mBottom = bottom;
142
143 return setData(key, TYPE_RECT, &r, sizeof(r));
144}
145
Marco Nelissen4256c972013-11-15 13:49:58 -0800146/**
147 * Note that the returned pointer becomes invalid when additional metadata is set.
148 */
Marco Nelissen22e668a2018-02-13 13:02:19 -0800149bool MetaData::findCString(uint32_t key, const char **value) const {
Andreas Huber20111aa2009-07-14 16:56:47 -0700150 uint32_t type;
151 const void *data;
152 size_t size;
153 if (!findData(key, &type, &data, &size) || type != TYPE_C_STRING) {
154 return false;
155 }
156
157 *value = (const char *)data;
158
159 return true;
160}
161
Marco Nelissen22e668a2018-02-13 13:02:19 -0800162bool MetaData::findInt32(uint32_t key, int32_t *value) const {
Marco Nelissen5b5d1f82015-09-01 08:10:09 -0700163 uint32_t type = 0;
Andreas Huber20111aa2009-07-14 16:56:47 -0700164 const void *data;
165 size_t size;
166 if (!findData(key, &type, &data, &size) || type != TYPE_INT32) {
167 return false;
168 }
169
Andreas Huber0c891992009-08-26 14:48:20 -0700170 CHECK_EQ(size, sizeof(*value));
Andreas Huber20111aa2009-07-14 16:56:47 -0700171
172 *value = *(int32_t *)data;
173
174 return true;
175}
176
Marco Nelissen22e668a2018-02-13 13:02:19 -0800177bool MetaData::findInt64(uint32_t key, int64_t *value) const {
Marco Nelissen5b5d1f82015-09-01 08:10:09 -0700178 uint32_t type = 0;
Andreas Huber48c948b2009-10-08 10:07:49 -0700179 const void *data;
180 size_t size;
181 if (!findData(key, &type, &data, &size) || type != TYPE_INT64) {
182 return false;
183 }
184
185 CHECK_EQ(size, sizeof(*value));
186
187 *value = *(int64_t *)data;
188
189 return true;
190}
191
Marco Nelissen22e668a2018-02-13 13:02:19 -0800192bool MetaData::findFloat(uint32_t key, float *value) const {
Marco Nelissen5b5d1f82015-09-01 08:10:09 -0700193 uint32_t type = 0;
Andreas Huber20111aa2009-07-14 16:56:47 -0700194 const void *data;
195 size_t size;
196 if (!findData(key, &type, &data, &size) || type != TYPE_FLOAT) {
197 return false;
198 }
199
Andreas Huber0c891992009-08-26 14:48:20 -0700200 CHECK_EQ(size, sizeof(*value));
Andreas Huber20111aa2009-07-14 16:56:47 -0700201
202 *value = *(float *)data;
203
204 return true;
205}
206
Marco Nelissen22e668a2018-02-13 13:02:19 -0800207bool MetaData::findPointer(uint32_t key, void **value) const {
Marco Nelissen5b5d1f82015-09-01 08:10:09 -0700208 uint32_t type = 0;
Andreas Huber20111aa2009-07-14 16:56:47 -0700209 const void *data;
210 size_t size;
211 if (!findData(key, &type, &data, &size) || type != TYPE_POINTER) {
212 return false;
213 }
214
Andreas Huber0c891992009-08-26 14:48:20 -0700215 CHECK_EQ(size, sizeof(*value));
Andreas Huber20111aa2009-07-14 16:56:47 -0700216
217 *value = *(void **)data;
218
219 return true;
220}
221
Andreas Huberf5ab57c2010-11-22 13:06:35 -0800222bool MetaData::findRect(
223 uint32_t key,
224 int32_t *left, int32_t *top,
Marco Nelissen22e668a2018-02-13 13:02:19 -0800225 int32_t *right, int32_t *bottom) const {
Marco Nelissen5b5d1f82015-09-01 08:10:09 -0700226 uint32_t type = 0;
Andreas Huberf5ab57c2010-11-22 13:06:35 -0800227 const void *data;
228 size_t size;
229 if (!findData(key, &type, &data, &size) || type != TYPE_RECT) {
230 return false;
231 }
232
233 CHECK_EQ(size, sizeof(Rect));
234
235 const Rect *r = (const Rect *)data;
236 *left = r->mLeft;
237 *top = r->mTop;
238 *right = r->mRight;
239 *bottom = r->mBottom;
240
241 return true;
242}
243
Andreas Huber20111aa2009-07-14 16:56:47 -0700244bool MetaData::setData(
245 uint32_t key, uint32_t type, const void *data, size_t size) {
246 bool overwrote_existing = true;
247
Marco Nelissen389f0fe2018-01-23 11:22:14 -0800248 ssize_t i = mInternalData->mItems.indexOfKey(key);
Andreas Huber20111aa2009-07-14 16:56:47 -0700249 if (i < 0) {
250 typed_data item;
Marco Nelissen389f0fe2018-01-23 11:22:14 -0800251 i = mInternalData->mItems.add(key, item);
Andreas Huber20111aa2009-07-14 16:56:47 -0700252
253 overwrote_existing = false;
254 }
255
Marco Nelissen389f0fe2018-01-23 11:22:14 -0800256 typed_data &item = mInternalData->mItems.editValueAt(i);
Andreas Huber20111aa2009-07-14 16:56:47 -0700257
258 item.setData(type, data, size);
259
260 return overwrote_existing;
261}
262
263bool MetaData::findData(uint32_t key, uint32_t *type,
264 const void **data, size_t *size) const {
Marco Nelissen389f0fe2018-01-23 11:22:14 -0800265 ssize_t i = mInternalData->mItems.indexOfKey(key);
Andreas Huber20111aa2009-07-14 16:56:47 -0700266
267 if (i < 0) {
268 return false;
269 }
270
Marco Nelissen389f0fe2018-01-23 11:22:14 -0800271 const typed_data &item = mInternalData->mItems.valueAt(i);
Andreas Huber20111aa2009-07-14 16:56:47 -0700272
273 item.getData(type, data, size);
274
275 return true;
276}
277
Oscar Rydhé328abde2011-01-27 14:01:24 +0100278bool MetaData::hasData(uint32_t key) const {
Marco Nelissen389f0fe2018-01-23 11:22:14 -0800279 ssize_t i = mInternalData->mItems.indexOfKey(key);
Oscar Rydhé328abde2011-01-27 14:01:24 +0100280
281 if (i < 0) {
282 return false;
283 }
284
285 return true;
286}
287
Andreas Huber20111aa2009-07-14 16:56:47 -0700288MetaData::typed_data::typed_data()
289 : mType(0),
290 mSize(0) {
291}
292
293MetaData::typed_data::~typed_data() {
294 clear();
295}
296
297MetaData::typed_data::typed_data(const typed_data &from)
298 : mType(from.mType),
299 mSize(0) {
Marco Nelissenf26400c2015-08-04 16:49:28 -0700300
301 void *dst = allocateStorage(from.mSize);
302 if (dst) {
303 memcpy(dst, from.storage(), mSize);
304 }
Andreas Huber20111aa2009-07-14 16:56:47 -0700305}
306
307MetaData::typed_data &MetaData::typed_data::operator=(
308 const MetaData::typed_data &from) {
309 if (this != &from) {
310 clear();
311 mType = from.mType;
Marco Nelissenf26400c2015-08-04 16:49:28 -0700312 void *dst = allocateStorage(from.mSize);
313 if (dst) {
314 memcpy(dst, from.storage(), mSize);
315 }
Andreas Huber20111aa2009-07-14 16:56:47 -0700316 }
317
318 return *this;
319}
320
321void MetaData::typed_data::clear() {
322 freeStorage();
323
324 mType = 0;
325}
326
327void MetaData::typed_data::setData(
328 uint32_t type, const void *data, size_t size) {
329 clear();
330
331 mType = type;
Marco Nelissenf26400c2015-08-04 16:49:28 -0700332
333 void *dst = allocateStorage(size);
334 if (dst) {
335 memcpy(dst, data, size);
Marco Nelissen566c70c2015-07-29 16:15:55 -0700336 }
Andreas Huber20111aa2009-07-14 16:56:47 -0700337}
338
339void MetaData::typed_data::getData(
340 uint32_t *type, const void **data, size_t *size) const {
341 *type = mType;
342 *size = mSize;
343 *data = storage();
344}
345
Marco Nelissenf26400c2015-08-04 16:49:28 -0700346void *MetaData::typed_data::allocateStorage(size_t size) {
Andreas Huber20111aa2009-07-14 16:56:47 -0700347 mSize = size;
348
349 if (usesReservoir()) {
Marco Nelissenf26400c2015-08-04 16:49:28 -0700350 return &u.reservoir;
Andreas Huber20111aa2009-07-14 16:56:47 -0700351 }
352
353 u.ext_data = malloc(mSize);
Marco Nelissenf26400c2015-08-04 16:49:28 -0700354 if (u.ext_data == NULL) {
355 ALOGE("Couldn't allocate %zu bytes for item", size);
356 mSize = 0;
357 }
358 return u.ext_data;
Andreas Huber20111aa2009-07-14 16:56:47 -0700359}
360
361void MetaData::typed_data::freeStorage() {
362 if (!usesReservoir()) {
363 if (u.ext_data) {
364 free(u.ext_data);
Christer Fletcherfca81252013-06-18 08:55:09 +0200365 u.ext_data = NULL;
Andreas Huber20111aa2009-07-14 16:56:47 -0700366 }
367 }
368
369 mSize = 0;
370}
371
Marco Nelissen69d3d8a2016-03-07 13:20:01 -0800372String8 MetaData::typed_data::asString(bool verbose) const {
Marco Nelissenfeba11f2012-03-21 12:27:00 -0700373 String8 out;
374 const void *data = storage();
375 switch(mType) {
376 case TYPE_NONE:
Kévin PETIT377b2ec2014-02-03 12:35:36 +0000377 out = String8::format("no type, size %zu)", mSize);
Marco Nelissenfeba11f2012-03-21 12:27:00 -0700378 break;
379 case TYPE_C_STRING:
380 out = String8::format("(char*) %s", (const char *)data);
381 break;
382 case TYPE_INT32:
383 out = String8::format("(int32_t) %d", *(int32_t *)data);
384 break;
385 case TYPE_INT64:
Kévin PETIT377b2ec2014-02-03 12:35:36 +0000386 out = String8::format("(int64_t) %" PRId64, *(int64_t *)data);
Marco Nelissenfeba11f2012-03-21 12:27:00 -0700387 break;
388 case TYPE_FLOAT:
389 out = String8::format("(float) %f", *(float *)data);
390 break;
391 case TYPE_POINTER:
392 out = String8::format("(void*) %p", *(void **)data);
393 break;
394 case TYPE_RECT:
395 {
396 const Rect *r = (const Rect *)data;
397 out = String8::format("Rect(%d, %d, %d, %d)",
398 r->mLeft, r->mTop, r->mRight, r->mBottom);
399 break;
400 }
401
402 default:
Kévin PETIT377b2ec2014-02-03 12:35:36 +0000403 out = String8::format("(unknown type %d, size %zu)", mType, mSize);
Marco Nelissen69d3d8a2016-03-07 13:20:01 -0800404 if (verbose && mSize <= 48) { // if it's less than three lines of hex data, dump it
Marco Nelissen56997122012-08-28 15:09:49 -0700405 AString foo;
406 hexdump(data, mSize, 0, &foo);
407 out.append("\n");
408 out.append(foo.c_str());
409 }
Marco Nelissenfeba11f2012-03-21 12:27:00 -0700410 break;
411 }
412 return out;
413}
414
415static void MakeFourCCString(uint32_t x, char *s) {
416 s[0] = x >> 24;
417 s[1] = (x >> 16) & 0xff;
418 s[2] = (x >> 8) & 0xff;
419 s[3] = x & 0xff;
420 s[4] = '\0';
421}
422
Marco Nelissen69d3d8a2016-03-07 13:20:01 -0800423String8 MetaData::toString() const {
424 String8 s;
Marco Nelissen389f0fe2018-01-23 11:22:14 -0800425 for (int i = mInternalData->mItems.size(); --i >= 0;) {
426 int32_t key = mInternalData->mItems.keyAt(i);
Marco Nelissen69d3d8a2016-03-07 13:20:01 -0800427 char cc[5];
428 MakeFourCCString(key, cc);
Marco Nelissen389f0fe2018-01-23 11:22:14 -0800429 const typed_data &item = mInternalData->mItems.valueAt(i);
Marco Nelissen69d3d8a2016-03-07 13:20:01 -0800430 s.appendFormat("%s: %s", cc, item.asString(false).string());
431 if (i != 0) {
432 s.append(", ");
433 }
434 }
435 return s;
436}
Marco Nelissenfeba11f2012-03-21 12:27:00 -0700437void MetaData::dumpToLog() const {
Marco Nelissen389f0fe2018-01-23 11:22:14 -0800438 for (int i = mInternalData->mItems.size(); --i >= 0;) {
439 int32_t key = mInternalData->mItems.keyAt(i);
Marco Nelissenfeba11f2012-03-21 12:27:00 -0700440 char cc[5];
441 MakeFourCCString(key, cc);
Marco Nelissen389f0fe2018-01-23 11:22:14 -0800442 const typed_data &item = mInternalData->mItems.valueAt(i);
Marco Nelissen69d3d8a2016-03-07 13:20:01 -0800443 ALOGI("%s: %s", cc, item.asString(true /* verbose */).string());
Marco Nelissenfeba11f2012-03-21 12:27:00 -0700444 }
445}
446
Marco Nelissenb2487f02015-09-01 13:23:23 -0700447status_t MetaData::writeToParcel(Parcel &parcel) {
Marco Nelissen72fcc3c2016-07-27 13:13:01 -0700448 status_t ret;
Marco Nelissen389f0fe2018-01-23 11:22:14 -0800449 size_t numItems = mInternalData->mItems.size();
Marco Nelissen72fcc3c2016-07-27 13:13:01 -0700450 ret = parcel.writeUint32(uint32_t(numItems));
451 if (ret) {
452 return ret;
453 }
Marco Nelissenb2487f02015-09-01 13:23:23 -0700454 for (size_t i = 0; i < numItems; i++) {
Marco Nelissen389f0fe2018-01-23 11:22:14 -0800455 int32_t key = mInternalData->mItems.keyAt(i);
456 const typed_data &item = mInternalData->mItems.valueAt(i);
Marco Nelissenb2487f02015-09-01 13:23:23 -0700457 uint32_t type;
458 const void *data;
459 size_t size;
460 item.getData(&type, &data, &size);
Marco Nelissen72fcc3c2016-07-27 13:13:01 -0700461 ret = parcel.writeInt32(key);
462 if (ret) {
463 return ret;
464 }
465 ret = parcel.writeUint32(type);
466 if (ret) {
467 return ret;
468 }
469 if (type == TYPE_NONE) {
470 android::Parcel::WritableBlob blob;
471 ret = parcel.writeUint32(static_cast<uint32_t>(size));
472 if (ret) {
473 return ret;
474 }
475 ret = parcel.writeBlob(size, false, &blob);
476 if (ret) {
477 return ret;
478 }
479 memcpy(blob.data(), data, size);
480 blob.release();
481 } else {
482 ret = parcel.writeByteArray(size, (uint8_t*)data);
483 if (ret) {
484 return ret;
485 }
486 }
Marco Nelissenb2487f02015-09-01 13:23:23 -0700487 }
488 return OK;
489}
490
491status_t MetaData::updateFromParcel(const Parcel &parcel) {
492 uint32_t numItems;
493 if (parcel.readUint32(&numItems) == OK) {
494
495 for (size_t i = 0; i < numItems; i++) {
496 int32_t key;
497 uint32_t type;
498 uint32_t size;
499 status_t ret = parcel.readInt32(&key);
500 ret |= parcel.readUint32(&type);
501 ret |= parcel.readUint32(&size);
502 if (ret != OK) {
503 break;
504 }
Marco Nelissen72fcc3c2016-07-27 13:13:01 -0700505 // copy data from Blob, which may be inline in Parcel storage,
506 // then advance position
507 if (type == TYPE_NONE) {
508 android::Parcel::ReadableBlob blob;
509 ret = parcel.readBlob(size, &blob);
510 if (ret != OK) {
511 break;
512 }
513 setData(key, type, blob.data(), size);
514 blob.release();
515 } else {
516 // copy data directly from Parcel storage, then advance position
517 setData(key, type, parcel.readInplace(size), size);
518 }
Marco Nelissenb2487f02015-09-01 13:23:23 -0700519 }
520
521 return OK;
522 }
523 ALOGW("no metadata in parcel");
524 return UNKNOWN_ERROR;
525}
526
527
528/* static */
529sp<MetaData> MetaData::createFromParcel(const Parcel &parcel) {
530
531 sp<MetaData> meta = new MetaData();
532 meta->updateFromParcel(parcel);
533 return meta;
534}
535
536
537
Andreas Huber20111aa2009-07-14 16:56:47 -0700538} // namespace android
539