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