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