blob: 60478c9aa081526470c5c564ac7d9b978f3b9cc4 [file] [log] [blame]
Marco Nelissen3d21ae32018-02-16 08:24:08 -08001/*
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>
Marco Nelissen3d21ae32018-02-16 08:24:08 -080020#include <utils/KeyedVector.h>
21#include <utils/Log.h>
22
23#include <stdlib.h>
24#include <string.h>
25
Sohail Nagaraj300e1482023-08-24 07:39:43 +000026#include <mutex>
27
Marco Nelissen3d21ae32018-02-16 08:24:08 -080028#include <media/stagefright/foundation/ADebug.h>
29#include <media/stagefright/foundation/AString.h>
30#include <media/stagefright/foundation/hexdump.h>
31#include <media/stagefright/MetaDataBase.h>
32
Colin Crossf8b5fe22021-12-15 14:59:00 -080033#if defined(__ANDROID__) && !defined(__ANDROID_VNDK__) && !defined(__ANDROID_APEX__)
Dongwon Kang97a21552019-08-28 11:22:33 -070034#include <binder/Parcel.h>
35#endif
36
Marco Nelissen3d21ae32018-02-16 08:24:08 -080037namespace android {
38
39struct MetaDataBase::typed_data {
40 typed_data();
41 ~typed_data();
42
43 typed_data(const MetaDataBase::typed_data &);
44 typed_data &operator=(const MetaDataBase::typed_data &);
45
46 void clear();
47 void setData(uint32_t type, const void *data, size_t size);
48 void getData(uint32_t *type, const void **data, size_t *size) const;
49 // may include hexdump of binary data if verbose=true
50 String8 asString(bool verbose) const;
51
52private:
53 uint32_t mType;
54 size_t mSize;
55
56 union {
57 void *ext_data;
58 float reservoir;
59 } u;
60
61 bool usesReservoir() const {
62 return mSize <= sizeof(u.reservoir);
63 }
64
65 void *allocateStorage(size_t size);
66 void freeStorage();
67
68 void *storage() {
69 return usesReservoir() ? &u.reservoir : u.ext_data;
70 }
71
72 const void *storage() const {
73 return usesReservoir() ? &u.reservoir : u.ext_data;
74 }
75};
76
77struct MetaDataBase::Rect {
78 int32_t mLeft, mTop, mRight, mBottom;
79};
80
81
82struct MetaDataBase::MetaDataInternal {
Sohail Nagaraj300e1482023-08-24 07:39:43 +000083 std::mutex mLock;
Marco Nelissen3d21ae32018-02-16 08:24:08 -080084 KeyedVector<uint32_t, MetaDataBase::typed_data> mItems;
85};
86
87
88MetaDataBase::MetaDataBase()
89 : mInternalData(new MetaDataInternal()) {
90}
91
92MetaDataBase::MetaDataBase(const MetaDataBase &from)
93 : mInternalData(new MetaDataInternal()) {
94 mInternalData->mItems = from.mInternalData->mItems;
95}
96
97MetaDataBase& MetaDataBase::operator = (const MetaDataBase &rhs) {
98 this->mInternalData->mItems = rhs.mInternalData->mItems;
99 return *this;
100}
101
102MetaDataBase::~MetaDataBase() {
103 clear();
104 delete mInternalData;
105}
106
107void MetaDataBase::clear() {
Sohail Nagaraj300e1482023-08-24 07:39:43 +0000108 std::lock_guard<std::mutex> guard(mInternalData->mLock);
Marco Nelissen3d21ae32018-02-16 08:24:08 -0800109 mInternalData->mItems.clear();
110}
111
112bool MetaDataBase::remove(uint32_t key) {
Sohail Nagaraj300e1482023-08-24 07:39:43 +0000113 std::lock_guard<std::mutex> guard(mInternalData->mLock);
Marco Nelissen3d21ae32018-02-16 08:24:08 -0800114 ssize_t i = mInternalData->mItems.indexOfKey(key);
115
116 if (i < 0) {
117 return false;
118 }
119
120 mInternalData->mItems.removeItemsAt(i);
121
122 return true;
123}
124
125bool MetaDataBase::setCString(uint32_t key, const char *value) {
126 return setData(key, TYPE_C_STRING, value, strlen(value) + 1);
127}
128
129bool MetaDataBase::setInt32(uint32_t key, int32_t value) {
130 return setData(key, TYPE_INT32, &value, sizeof(value));
131}
132
133bool MetaDataBase::setInt64(uint32_t key, int64_t value) {
134 return setData(key, TYPE_INT64, &value, sizeof(value));
135}
136
137bool MetaDataBase::setFloat(uint32_t key, float value) {
138 return setData(key, TYPE_FLOAT, &value, sizeof(value));
139}
140
141bool MetaDataBase::setPointer(uint32_t key, void *value) {
142 return setData(key, TYPE_POINTER, &value, sizeof(value));
143}
144
145bool MetaDataBase::setRect(
146 uint32_t key,
147 int32_t left, int32_t top,
148 int32_t right, int32_t bottom) {
149 Rect r;
150 r.mLeft = left;
151 r.mTop = top;
152 r.mRight = right;
153 r.mBottom = bottom;
154
155 return setData(key, TYPE_RECT, &r, sizeof(r));
156}
157
158/**
159 * Note that the returned pointer becomes invalid when additional metadata is set.
160 */
161bool MetaDataBase::findCString(uint32_t key, const char **value) const {
162 uint32_t type;
163 const void *data;
164 size_t size;
165 if (!findData(key, &type, &data, &size) || type != TYPE_C_STRING) {
166 return false;
167 }
168
169 *value = (const char *)data;
170
171 return true;
172}
173
174bool MetaDataBase::findInt32(uint32_t key, int32_t *value) const {
175 uint32_t type = 0;
176 const void *data;
177 size_t size;
178 if (!findData(key, &type, &data, &size) || type != TYPE_INT32) {
179 return false;
180 }
181
182 CHECK_EQ(size, sizeof(*value));
183
184 *value = *(int32_t *)data;
185
186 return true;
187}
188
189bool MetaDataBase::findInt64(uint32_t key, int64_t *value) const {
190 uint32_t type = 0;
191 const void *data;
192 size_t size;
193 if (!findData(key, &type, &data, &size) || type != TYPE_INT64) {
194 return false;
195 }
196
197 CHECK_EQ(size, sizeof(*value));
198
199 *value = *(int64_t *)data;
200
201 return true;
202}
203
204bool MetaDataBase::findFloat(uint32_t key, float *value) const {
205 uint32_t type = 0;
206 const void *data;
207 size_t size;
208 if (!findData(key, &type, &data, &size) || type != TYPE_FLOAT) {
209 return false;
210 }
211
212 CHECK_EQ(size, sizeof(*value));
213
214 *value = *(float *)data;
215
216 return true;
217}
218
219bool MetaDataBase::findPointer(uint32_t key, void **value) const {
220 uint32_t type = 0;
221 const void *data;
222 size_t size;
223 if (!findData(key, &type, &data, &size) || type != TYPE_POINTER) {
224 return false;
225 }
226
227 CHECK_EQ(size, sizeof(*value));
228
229 *value = *(void **)data;
230
231 return true;
232}
233
234bool MetaDataBase::findRect(
235 uint32_t key,
236 int32_t *left, int32_t *top,
237 int32_t *right, int32_t *bottom) const {
238 uint32_t type = 0;
239 const void *data;
240 size_t size;
241 if (!findData(key, &type, &data, &size) || type != TYPE_RECT) {
242 return false;
243 }
244
245 CHECK_EQ(size, sizeof(Rect));
246
247 const Rect *r = (const Rect *)data;
248 *left = r->mLeft;
249 *top = r->mTop;
250 *right = r->mRight;
251 *bottom = r->mBottom;
252
253 return true;
254}
255
256bool MetaDataBase::setData(
257 uint32_t key, uint32_t type, const void *data, size_t size) {
258 bool overwrote_existing = true;
259
Sohail Nagaraj300e1482023-08-24 07:39:43 +0000260 std::lock_guard<std::mutex> guard(mInternalData->mLock);
Marco Nelissen3d21ae32018-02-16 08:24:08 -0800261 ssize_t i = mInternalData->mItems.indexOfKey(key);
262 if (i < 0) {
263 typed_data item;
264 i = mInternalData->mItems.add(key, item);
265
266 overwrote_existing = false;
267 }
268
269 typed_data &item = mInternalData->mItems.editValueAt(i);
270
271 item.setData(type, data, size);
272
273 return overwrote_existing;
274}
275
276bool MetaDataBase::findData(uint32_t key, uint32_t *type,
277 const void **data, size_t *size) const {
Sohail Nagaraj300e1482023-08-24 07:39:43 +0000278 std::lock_guard<std::mutex> guard(mInternalData->mLock);
Marco Nelissen3d21ae32018-02-16 08:24:08 -0800279 ssize_t i = mInternalData->mItems.indexOfKey(key);
280
281 if (i < 0) {
282 return false;
283 }
284
285 const typed_data &item = mInternalData->mItems.valueAt(i);
286
287 item.getData(type, data, size);
288
289 return true;
290}
291
292bool MetaDataBase::hasData(uint32_t key) const {
Sohail Nagaraj300e1482023-08-24 07:39:43 +0000293 std::lock_guard<std::mutex> guard(mInternalData->mLock);
Marco Nelissen3d21ae32018-02-16 08:24:08 -0800294 ssize_t i = mInternalData->mItems.indexOfKey(key);
295
296 if (i < 0) {
297 return false;
298 }
299
300 return true;
301}
302
303MetaDataBase::typed_data::typed_data()
304 : mType(0),
305 mSize(0) {
306}
307
308MetaDataBase::typed_data::~typed_data() {
309 clear();
310}
311
312MetaDataBase::typed_data::typed_data(const typed_data &from)
313 : mType(from.mType),
314 mSize(0) {
315
316 void *dst = allocateStorage(from.mSize);
317 if (dst) {
318 memcpy(dst, from.storage(), mSize);
319 }
320}
321
322MetaDataBase::typed_data &MetaDataBase::typed_data::operator=(
323 const MetaDataBase::typed_data &from) {
324 if (this != &from) {
325 clear();
326 mType = from.mType;
327 void *dst = allocateStorage(from.mSize);
328 if (dst) {
329 memcpy(dst, from.storage(), mSize);
330 }
331 }
332
333 return *this;
334}
335
336void MetaDataBase::typed_data::clear() {
337 freeStorage();
338
339 mType = 0;
340}
341
342void MetaDataBase::typed_data::setData(
343 uint32_t type, const void *data, size_t size) {
344 clear();
345
346 mType = type;
347
348 void *dst = allocateStorage(size);
349 if (dst) {
350 memcpy(dst, data, size);
351 }
352}
353
354void MetaDataBase::typed_data::getData(
355 uint32_t *type, const void **data, size_t *size) const {
356 *type = mType;
357 *size = mSize;
358 *data = storage();
359}
360
361void *MetaDataBase::typed_data::allocateStorage(size_t size) {
362 mSize = size;
363
364 if (usesReservoir()) {
365 return &u.reservoir;
366 }
367
368 u.ext_data = malloc(mSize);
369 if (u.ext_data == NULL) {
370 ALOGE("Couldn't allocate %zu bytes for item", size);
371 mSize = 0;
372 }
373 return u.ext_data;
374}
375
376void MetaDataBase::typed_data::freeStorage() {
377 if (!usesReservoir()) {
378 if (u.ext_data) {
379 free(u.ext_data);
380 u.ext_data = NULL;
381 }
382 }
383
384 mSize = 0;
385}
386
387String8 MetaDataBase::typed_data::asString(bool verbose) const {
388 String8 out;
389 const void *data = storage();
390 switch(mType) {
391 case TYPE_NONE:
392 out = String8::format("no type, size %zu)", mSize);
393 break;
394 case TYPE_C_STRING:
395 out = String8::format("(char*) %s", (const char *)data);
396 break;
397 case TYPE_INT32:
398 out = String8::format("(int32_t) %d", *(int32_t *)data);
399 break;
400 case TYPE_INT64:
401 out = String8::format("(int64_t) %" PRId64, *(int64_t *)data);
402 break;
403 case TYPE_FLOAT:
404 out = String8::format("(float) %f", *(float *)data);
405 break;
406 case TYPE_POINTER:
407 out = String8::format("(void*) %p", *(void **)data);
408 break;
409 case TYPE_RECT:
410 {
411 const Rect *r = (const Rect *)data;
412 out = String8::format("Rect(%d, %d, %d, %d)",
413 r->mLeft, r->mTop, r->mRight, r->mBottom);
414 break;
415 }
416
417 default:
418 out = String8::format("(unknown type %d, size %zu)", mType, mSize);
419 if (verbose && mSize <= 48) { // if it's less than three lines of hex data, dump it
420 AString foo;
421 hexdump(data, mSize, 0, &foo);
422 out.append("\n");
423 out.append(foo.c_str());
424 }
425 break;
426 }
427 return out;
428}
429
430static void MakeFourCCString(uint32_t x, char *s) {
431 s[0] = x >> 24;
432 s[1] = (x >> 16) & 0xff;
433 s[2] = (x >> 8) & 0xff;
434 s[3] = x & 0xff;
435 s[4] = '\0';
436}
437
438String8 MetaDataBase::toString() const {
439 String8 s;
Sohail Nagaraj300e1482023-08-24 07:39:43 +0000440 std::lock_guard<std::mutex> guard(mInternalData->mLock);
Marco Nelissen3d21ae32018-02-16 08:24:08 -0800441 for (int i = mInternalData->mItems.size(); --i >= 0;) {
442 int32_t key = mInternalData->mItems.keyAt(i);
443 char cc[5];
444 MakeFourCCString(key, cc);
445 const typed_data &item = mInternalData->mItems.valueAt(i);
Tomasz Wasilczyk946a39f2023-08-15 21:11:31 +0000446 s.appendFormat("%s: %s", cc, item.asString(false).c_str());
Marco Nelissen3d21ae32018-02-16 08:24:08 -0800447 if (i != 0) {
448 s.append(", ");
449 }
450 }
451 return s;
452}
453
454void MetaDataBase::dumpToLog() const {
Sohail Nagaraj300e1482023-08-24 07:39:43 +0000455 std::lock_guard<std::mutex> guard(mInternalData->mLock);
Marco Nelissen3d21ae32018-02-16 08:24:08 -0800456 for (int i = mInternalData->mItems.size(); --i >= 0;) {
457 int32_t key = mInternalData->mItems.keyAt(i);
458 char cc[5];
459 MakeFourCCString(key, cc);
460 const typed_data &item = mInternalData->mItems.valueAt(i);
Tomasz Wasilczyk946a39f2023-08-15 21:11:31 +0000461 ALOGI("%s: %s", cc, item.asString(true /* verbose */).c_str());
Marco Nelissen3d21ae32018-02-16 08:24:08 -0800462 }
463}
464
Colin Crossf8b5fe22021-12-15 14:59:00 -0800465#if defined(__ANDROID__) && !defined(__ANDROID_VNDK__) && !defined(__ANDROID_APEX__)
Marco Nelissen3d21ae32018-02-16 08:24:08 -0800466status_t MetaDataBase::writeToParcel(Parcel &parcel) {
467 status_t ret;
Sohail Nagaraj300e1482023-08-24 07:39:43 +0000468 std::lock_guard<std::mutex> guard(mInternalData->mLock);
Marco Nelissen3d21ae32018-02-16 08:24:08 -0800469 size_t numItems = mInternalData->mItems.size();
470 ret = parcel.writeUint32(uint32_t(numItems));
471 if (ret) {
472 return ret;
473 }
474 for (size_t i = 0; i < numItems; i++) {
475 int32_t key = mInternalData->mItems.keyAt(i);
476 const typed_data &item = mInternalData->mItems.valueAt(i);
477 uint32_t type;
478 const void *data;
479 size_t size;
480 item.getData(&type, &data, &size);
481 ret = parcel.writeInt32(key);
482 if (ret) {
483 return ret;
484 }
485 ret = parcel.writeUint32(type);
486 if (ret) {
487 return ret;
488 }
489 if (type == TYPE_NONE) {
490 android::Parcel::WritableBlob blob;
491 ret = parcel.writeUint32(static_cast<uint32_t>(size));
492 if (ret) {
493 return ret;
494 }
495 ret = parcel.writeBlob(size, false, &blob);
496 if (ret) {
497 return ret;
498 }
499 memcpy(blob.data(), data, size);
500 blob.release();
501 } else {
502 ret = parcel.writeByteArray(size, (uint8_t*)data);
503 if (ret) {
504 return ret;
505 }
506 }
507 }
508 return OK;
509}
510
511status_t MetaDataBase::updateFromParcel(const Parcel &parcel) {
512 uint32_t numItems;
513 if (parcel.readUint32(&numItems) == OK) {
514
515 for (size_t i = 0; i < numItems; i++) {
516 int32_t key;
517 uint32_t type;
518 uint32_t size;
519 status_t ret = parcel.readInt32(&key);
520 ret |= parcel.readUint32(&type);
521 ret |= parcel.readUint32(&size);
522 if (ret != OK) {
523 break;
524 }
525 // copy data from Blob, which may be inline in Parcel storage,
526 // then advance position
527 if (type == TYPE_NONE) {
528 android::Parcel::ReadableBlob blob;
529 ret = parcel.readBlob(size, &blob);
530 if (ret != OK) {
531 break;
532 }
533 setData(key, type, blob.data(), size);
534 blob.release();
Ray Essick2d1072c2022-04-28 14:58:43 -0700535 } else if (type == TYPE_C_STRING) {
536 // copy data directly from Parcel storage, then advance position
537 // NB: readInplace() bumps position, it is NOT idempotent.
538 const void *src = parcel.readInplace(size);
539 char *str = (char *) src;
540 if (src == nullptr || size == 0 || str[size-1] != '\0') {
541 char ccKey[5];
542 MakeFourCCString(key, ccKey);
543 if (src == nullptr) {
544 ALOGW("ignoring key '%s' string with no data (expected %d)", ccKey, size);
545 } else {
546 ALOGW("ignoring key '%s': unterminated string of %d bytes", ccKey, size);
547 }
548 } else {
549 setData(key, type, src, size);
550 }
Marco Nelissen3d21ae32018-02-16 08:24:08 -0800551 } else {
552 // copy data directly from Parcel storage, then advance position
Ray Essick2d1072c2022-04-28 14:58:43 -0700553 // verify that the received size is enough
554 uint32_t needed = 0;
555 switch (type) {
556 case TYPE_INT32:
557 needed = sizeof(int32_t);
558 break;
559 case TYPE_INT64:
560 needed = sizeof(int64_t);
561 break;
562 case TYPE_FLOAT:
563 needed = sizeof(float);
564 break;
565 case TYPE_POINTER:
566 // NB: this rejects passing between 32-bit and 64-bit space.
567 needed = sizeof(void*);
568 break;
569 case TYPE_RECT:
570 needed = sizeof(Rect);
571 break;
572 default:
573 // non-standard entities can be any size >= 0
574 needed = 0;
575 break;
576 }
577 const void *src = parcel.readInplace(size);
578 if (src == nullptr || (needed != 0 && size != needed)) {
579 char ccKey[5];
580 MakeFourCCString(key, ccKey);
581 char ccType[5];
582 MakeFourCCString(type, ccType);
583 if (src == nullptr) {
584 ALOGW("ignoring key '%s' type '%s' missing data (expected %d)",
585 ccKey, ccType, size);
586 } else {
587 ALOGW("ignoring key '%s': type '%s' bytes: expected %d != %d received",
588 ccKey, ccType, needed, size);
589 }
590 } else {
591 setData(key, type, src, size);
592 }
Marco Nelissen3d21ae32018-02-16 08:24:08 -0800593 }
594 }
595
596 return OK;
597 }
598 ALOGW("no metadata in parcel");
599 return UNKNOWN_ERROR;
600}
Colin Crossf8b5fe22021-12-15 14:59:00 -0800601#endif // defined(__ANDROID__) && !defined(__ANDROID_VNDK__) && !defined(__ANDROID_APEX__)
Marco Nelissen3d21ae32018-02-16 08:24:08 -0800602
603} // namespace android
604