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 "ESDS"
19#include <utils/Log.h>
20
21#include <media/stagefright/foundation/ByteUtils.h>
22
23#include "include/ESDS.h"
24
25#include <string.h>
26
27namespace android {
28
29ESDS::ESDS(const void *data, size_t size)
30    : mData(new uint8_t[size]),
31      mSize(size),
32      mInitCheck(NO_INIT),
33      mDecoderSpecificOffset(0),
34      mDecoderSpecificLength(0),
35      mObjectTypeIndication(0) {
36    memcpy(mData, data, size);
37
38    mInitCheck = parse();
39}
40
41ESDS::~ESDS() {
42    delete[] mData;
43    mData = NULL;
44}
45
46status_t ESDS::InitCheck() const {
47    return mInitCheck;
48}
49
50status_t ESDS::getObjectTypeIndication(uint8_t *objectTypeIndication) const {
51    if (mInitCheck != OK) {
52        return mInitCheck;
53    }
54
55    *objectTypeIndication = mObjectTypeIndication;
56
57    return OK;
58}
59
60status_t ESDS::getCodecSpecificInfo(const void **data, size_t *size) const {
61    if (mInitCheck != OK) {
62        return mInitCheck;
63    }
64
65    *data = &mData[mDecoderSpecificOffset];
66    *size = mDecoderSpecificLength;
67
68    return OK;
69}
70
71status_t ESDS::skipDescriptorHeader(
72        size_t offset, size_t size,
73        uint8_t *tag, size_t *data_offset, size_t *data_size) const {
74    if (size == 0) {
75        return ERROR_MALFORMED;
76    }
77
78    *tag = mData[offset++];
79    --size;
80
81    *data_size = 0;
82    bool more;
83    do {
84        if (size == 0) {
85            return ERROR_MALFORMED;
86        }
87
88        uint8_t x = mData[offset++];
89        --size;
90
91        *data_size = (*data_size << 7) | (x & 0x7f);
92        more = (x & 0x80) != 0;
93    }
94    while (more);
95
96    ALOGV("tag=0x%02x data_size=%zu", *tag, *data_size);
97
98    if (*data_size > size) {
99        return ERROR_MALFORMED;
100    }
101
102    *data_offset = offset;
103
104    return OK;
105}
106
107status_t ESDS::parse() {
108    uint8_t tag;
109    size_t data_offset;
110    size_t data_size;
111    status_t err =
112        skipDescriptorHeader(0, mSize, &tag, &data_offset, &data_size);
113
114    if (err != OK) {
115        return err;
116    }
117
118    if (tag != kTag_ESDescriptor) {
119        return ERROR_MALFORMED;
120    }
121
122    return parseESDescriptor(data_offset, data_size);
123}
124
125status_t ESDS::parseESDescriptor(size_t offset, size_t size) {
126    if (size < 3) {
127        return ERROR_MALFORMED;
128    }
129
130    offset += 2;  // skip ES_ID
131    size -= 2;
132
133    unsigned streamDependenceFlag = mData[offset] & 0x80;
134    unsigned URL_Flag = mData[offset] & 0x40;
135    unsigned OCRstreamFlag = mData[offset] & 0x20;
136
137    ++offset;
138    --size;
139
140    if (streamDependenceFlag) {
141        if (size < 2)
142            return ERROR_MALFORMED;
143        offset += 2;
144        size -= 2;
145    }
146
147    if (URL_Flag) {
148        if (offset >= size) {
149            return ERROR_MALFORMED;
150        }
151        unsigned URLlength = mData[offset];
152        if (URLlength >= size)
153            return ERROR_MALFORMED;
154        offset += URLlength + 1;
155        size -= URLlength + 1;
156    }
157
158    if (OCRstreamFlag) {
159        if (size < 2)
160            return ERROR_MALFORMED;
161        offset += 2;
162        size -= 2;
163
164        if ((offset >= size || mData[offset] != kTag_DecoderConfigDescriptor)
165                && offset - 2 < size
166                && mData[offset - 2] == kTag_DecoderConfigDescriptor) {
167            // Content found "in the wild" had OCRstreamFlag set but was
168            // missing OCR_ES_Id, the decoder config descriptor immediately
169            // followed instead.
170            offset -= 2;
171            size += 2;
172
173            ALOGW("Found malformed 'esds' atom, ignoring missing OCR_ES_Id.");
174        }
175    }
176
177    if (offset >= size) {
178        return ERROR_MALFORMED;
179    }
180
181    uint8_t tag;
182    size_t sub_offset, sub_size;
183    status_t err = skipDescriptorHeader(
184            offset, size, &tag, &sub_offset, &sub_size);
185
186    if (err != OK) {
187        return err;
188    }
189
190    if (tag != kTag_DecoderConfigDescriptor) {
191        return ERROR_MALFORMED;
192    }
193
194    err = parseDecoderConfigDescriptor(sub_offset, sub_size);
195
196    return err;
197}
198
199status_t ESDS::getBitRate(uint32_t *brateMax, uint32_t *brateAvg) const {
200    if (mInitCheck != OK) {
201        return mInitCheck;
202    }
203
204    *brateMax = mBitRateMax;
205    *brateAvg = mBitRateAvg;
206
207    return OK;
208};
209
210status_t ESDS::parseDecoderConfigDescriptor(size_t offset, size_t size) {
211    if (size < 13) {
212        return ERROR_MALFORMED;
213    }
214
215    mObjectTypeIndication = mData[offset];
216    mBitRateMax = U32_AT(mData + offset + 5);
217    mBitRateAvg = U32_AT(mData + offset + 9);
218
219    offset += 13;
220    size -= 13;
221
222    if (size == 0) {
223        mDecoderSpecificOffset = 0;
224        mDecoderSpecificLength = 0;
225        return OK;
226    }
227
228    uint8_t tag;
229    size_t sub_offset, sub_size;
230    status_t err = skipDescriptorHeader(
231            offset, size, &tag, &sub_offset, &sub_size);
232
233    if (err != OK) {
234        return err;
235    }
236
237    if (tag != kTag_DecoderSpecificInfo) {
238        return ERROR_MALFORMED;
239    }
240
241    mDecoderSpecificOffset = sub_offset;
242    mDecoderSpecificLength = sub_size;
243
244    return OK;
245}
246
247}  // namespace android
248
249