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 
25 namespace android {
26 
ESDS(const void * data,size_t size)27 ESDS::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 
~ESDS()39 ESDS::~ESDS() {
40     delete[] mData;
41     mData = NULL;
42 }
43 
InitCheck() const44 status_t ESDS::InitCheck() const {
45     return mInitCheck;
46 }
47 
getObjectTypeIndication(uint8_t * objectTypeIndication) const48 status_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 
getCodecSpecificInfo(const void ** data,size_t * size) const58 status_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 
skipDescriptorHeader(size_t offset,size_t size,uint8_t * tag,size_t * data_offset,size_t * data_size) const69 status_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 
parse()105 status_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 
parseESDescriptor(size_t offset,size_t size)123 status_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 
parseDecoderConfigDescriptor(size_t offset,size_t size)191 status_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