1 /*
2 * The contents of this file are subject to the Mozilla Public
3 * License Version 1.1 (the "License"); you may not use this file
4 * except in compliance with the License. You may obtain a copy of
5 * the License at http://www.mozilla.org/MPL/
6 *
7 * Software distributed under the License is distributed on an "AS
8 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
9 * implied. See the License for the specific language governing
10 * rights and limitations under the License.
11 *
12 * The Original Code is MPEG4IP.
13 *
14 * The Initial Developer of the Original Code is Cisco Systems Inc.
15 * Portions created by Cisco Systems Inc. are
16 * Copyright (C) Cisco Systems Inc. 2001-2005. All Rights Reserved.
17 *
18 * Contributor(s):
19 * Dave Mackie dmackie@cisco.com
20 * Bill May wmay@cisco.com
21 */
22
23 #include "src/impl.h"
24
25 namespace mp4v2 { namespace impl {
26
27 ///////////////////////////////////////////////////////////////////////////////
28
MP4NameFirstMatches(const char * s1,const char * s2)29 bool MP4NameFirstMatches(const char* s1, const char* s2)
30 {
31 if (s1 == NULL || *s1 == '\0' || s2 == NULL || *s2 == '\0') {
32 return false;
33 }
34
35 if (*s2 == '*') {
36 return true;
37 }
38
39 while (*s1 != '\0') {
40 if (*s2 == '\0' || strchr("[.", *s2)) {
41 break;
42 }
43 if (tolower(*s1) != tolower(*s2)) {
44 return false;
45 }
46 s1++;
47 s2++;
48 }
49 return true;
50 }
51
MP4NameFirstIndex(const char * s,uint32_t * pIndex)52 bool MP4NameFirstIndex(const char* s, uint32_t* pIndex)
53 {
54 if (s == NULL) {
55 return false;
56 }
57
58 while (*s != '\0' && *s != '.') {
59 if (*s == '[') {
60 s++;
61 ASSERT(pIndex);
62 if (sscanf(s, "%u", pIndex) != 1) {
63 return false;
64 }
65 return true;
66 }
67 s++;
68 }
69 return false;
70 }
71
MP4NameFirst(const char * s)72 char* MP4NameFirst(const char *s)
73 {
74 if (s == NULL) {
75 return NULL;
76 }
77
78 const char* end = s;
79
80 while (*end != '\0' && *end != '.') {
81 end++;
82 }
83
84 char* first = (char*)MP4Calloc((end - s) + 1);
85
86 if (first) {
87 strncpy(first, s, end - s);
88 }
89
90 return first;
91 }
92
MP4NameAfterFirst(const char * s)93 const char* MP4NameAfterFirst(const char *s)
94 {
95 if (s == NULL) {
96 return NULL;
97 }
98
99 while (*s != '\0') {
100 if (*s == '.') {
101 s++;
102 if (*s == '\0') {
103 return NULL;
104 }
105 return s;
106 }
107 s++;
108 }
109 return NULL;
110 }
111
MP4ToBase16(const uint8_t * pData,uint32_t dataSize)112 char* MP4ToBase16(const uint8_t* pData, uint32_t dataSize)
113 {
114 if (dataSize) {
115 ASSERT(pData);
116 }
117 uint32_t size = 2 * dataSize + 1;
118 char* s = (char*)MP4Calloc(size);
119
120 uint32_t i, j;
121 for (i = 0, j = 0; i < dataSize; i++) {
122 size -= snprintf(&s[j], size, "%02x", pData[i]);
123 j += 2;
124 }
125
126 return s; /* N.B. caller is responsible for free'ing s */
127 }
128
MP4ToBase64(const uint8_t * pData,uint32_t dataSize)129 char* MP4ToBase64(const uint8_t* pData, uint32_t dataSize)
130 {
131 if (pData == NULL || dataSize == 0) return NULL;
132
133 static const char encoding[64] = {
134 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P',
135 'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f',
136 'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v',
137 'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/'
138 };
139
140 char* s = (char*)MP4Calloc((((dataSize + 2) * 4) / 3) + 1);
141
142 const uint8_t* src = pData;
143 if (pData == NULL) return NULL;
144 char* dest = s;
145 uint32_t numGroups = dataSize / 3;
146
147 for (uint32_t i = 0; i < numGroups; i++) {
148 *dest++ = encoding[src[0] >> 2];
149 *dest++ = encoding[((src[0] & 0x03) << 4) | (src[1] >> 4)];
150 *dest++ = encoding[((src[1] & 0x0F) << 2) | (src[2] >> 6)];
151 *dest++ = encoding[src[2] & 0x3F];
152 src += 3;
153 }
154
155 if (dataSize % 3 == 1) {
156 *dest++ = encoding[src[0] >> 2];
157 *dest++ = encoding[((src[0] & 0x03) << 4)];
158 *dest++ = '=';
159 *dest++ = '=';
160 } else if (dataSize % 3 == 2) {
161 *dest++ = encoding[src[0] >> 2];
162 *dest++ = encoding[((src[0] & 0x03) << 4) | (src[1] >> 4)];
163 *dest++ = encoding[((src[1] & 0x0F) << 2)];
164 *dest++ = '=';
165 }
166 *dest = '\0';
167 return s; /* N.B. caller is responsible for free'ing s */
168 }
169
convertBase64(const char data,uint8_t * value)170 static bool convertBase64 (const char data, uint8_t *value)
171 {
172 static const uint8_t decodingarr64[128] = {
173 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
174 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
175 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
176 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
177 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
178 0xff, 0xff, 0xff, 0x3e, 0xff, 0xff, 0xff, 0x3f,
179 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b,
180 0x3c, 0x3d, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
181 0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
182 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
183 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
184 0x17, 0x18, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff,
185 0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
186 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
187 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
188 0x31, 0x32, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff,
189 };
190 uint8_t index = (uint8_t)data;
191 if ((index & 0x80) != 0) return false;
192
193 if (decodingarr64[index] == 0xff) return false;
194 *value = decodingarr64[index];
195 return true;
196 }
197
198 }} // namespace mp4v2::impl
199
200 extern "C"
Base64ToBinary(const char * pData,uint32_t decodeSize,uint32_t * pDataSize)201 uint8_t *Base64ToBinary (const char *pData, uint32_t decodeSize, uint32_t *pDataSize)
202 {
203 uint8_t *ret;
204 uint32_t size, ix, groups;
205 if (pData == NULL || decodeSize == 0 || pDataSize == NULL)
206 return NULL;
207
208 if ((decodeSize % 4) != 0) {
209 // must be multiples of 4 characters
210 return NULL;
211 }
212 size = (decodeSize * 3) / 4;
213 groups = decodeSize / 4;
214 ret = (uint8_t *)mp4v2::impl::MP4Calloc(size);
215 if (ret == NULL) return NULL;
216 for (ix = 0; ix < groups; ix++) {
217 uint8_t value[4];
218 for (uint8_t jx = 0; jx < 4; jx++) {
219 if (pData[jx] == '=') {
220 if (ix != (groups - 1)) {
221 free(ret);
222 return NULL;
223 }
224 size--;
225 value[jx] = 0;
226 } else if (mp4v2::impl::convertBase64(pData[jx], &value[jx]) == false) {
227 free(ret);
228 return NULL;
229 }
230 }
231 ret[(ix * 3)] = value[0] << 2 | ((value[1] >> 4) & 0x3);
232 ret[(ix * 3) + 1] = (value[1] << 4) | (value[2] >> 2 & 0xf);
233 ret[(ix * 3) + 2] = ((value[2] & 0x3) << 6) | value[3];
234 pData += 4;
235 }
236 *pDataSize = size;
237 return ret;
238 }
239
240 namespace mp4v2 { namespace impl {
241
242 // log2 of value, rounded up
ilog2(uint64_t value)243 static uint8_t ilog2(uint64_t value)
244 {
245 uint64_t powerOf2 = 1;
246 for (uint8_t i = 0; i < 64; i++) {
247 if (value <= powerOf2) {
248 return i;
249 }
250 powerOf2 <<= 1;
251 }
252 return 64;
253 }
254
MP4ConvertTime(uint64_t t,uint32_t oldTimeScale,uint32_t newTimeScale)255 uint64_t MP4ConvertTime(uint64_t t,
256 uint32_t oldTimeScale, uint32_t newTimeScale)
257 {
258 // avoid float point exception
259 if (oldTimeScale == 0) {
260 throw new Exception("division by zero", __FILE__, __LINE__, __FUNCTION__ );
261 }
262
263 if (oldTimeScale == newTimeScale) return t;
264
265 // check if we can safely use integer operations
266 if (ilog2(t) + ilog2(newTimeScale) <= 64) {
267 return (t * newTimeScale) / oldTimeScale;
268 }
269
270 // final resort is to use floating point
271 double d = (double)newTimeScale;
272 d *= double(t);
273 d /= (double)oldTimeScale;
274 d += 0.5; // round up.
275
276 return (uint64_t)d;
277 }
278
MP4NormalizeTrackType(const char * type)279 const char* MP4NormalizeTrackType (const char* type)
280 {
281 if (!strcasecmp(type, "vide")
282 || !strcasecmp(type, "video")
283 || !strcasecmp(type, "mp4v")
284 || !strcasecmp(type, "avc1")
285 || !strcasecmp(type, "s263") // 3GPP H.263
286 || !strcasecmp(type, "encv")) {
287 return MP4_VIDEO_TRACK_TYPE;
288 }
289
290 if (!strcasecmp(type, "soun")
291 || !strcasecmp(type, "sound")
292 || !strcasecmp(type, "audio")
293 || !strcasecmp(type, "enca")
294 || !strcasecmp(type, "samr") // 3GPP AMR
295 || !strcasecmp(type, "sawb") // 3GPP AMR/WB
296 || !strcasecmp(type, "mp4a")) {
297 return MP4_AUDIO_TRACK_TYPE;
298 }
299
300 if (!strcasecmp(type, "sdsm")
301 || !strcasecmp(type, "scene")
302 || !strcasecmp(type, "bifs")) {
303 return MP4_SCENE_TRACK_TYPE;
304 }
305
306 if (!strcasecmp(type, "odsm")
307 || !strcasecmp(type, "od")) {
308 return MP4_OD_TRACK_TYPE;
309 }
310 if (strcasecmp(type, "cntl") == 0) {
311 return MP4_CNTL_TRACK_TYPE;
312 }
313
314 log.verbose1f("Attempt to normalize %s did not match",type);
315
316 return type;
317 }
318
MP4GetAbsTimestamp()319 MP4Timestamp MP4GetAbsTimestamp() {
320 /* MP4 epoch is midnight, January 1, 1904
321 * offset from midnight, January 1, 1970 is 2082844800 seconds
322 * 208284480 is (((1970 - 1904) * 365) + 17) * 24 * 60 * 60
323 */
324 return time::getLocalTimeSeconds() + 2082844800;
325 }
326
327 ///////////////////////////////////////////////////////////////////////////////
328
STRTOINT32(const char * s)329 uint32_t STRTOINT32( const char* s )
330 {
331 #if defined( MP4V2_INTSTRING_ALIGNMENT )
332 // it seems ARM integer instructions require 4-byte alignment so we
333 // manually copy string-data into the integer before performing ops
334 uint32_t tmp;
335 memcpy( &tmp, s, sizeof(tmp) );
336 return MP4V2_NTOHL( tmp );
337 #else
338 return MP4V2_NTOHL(*(uint32_t *)s);
339 #endif
340 }
341
INT32TOSTR(uint32_t i,char * s)342 void INT32TOSTR( uint32_t i, char* s )
343 {
344 #if defined( MP4V2_INTSTRING_ALIGNMENT )
345 // it seems ARM integer instructions require 4-byte alignment so we
346 // manually copy string-data into the integer before performing ops
347 uint32_t tmp = MP4V2_HTONL( i );
348 memcpy( s, &tmp, sizeof(tmp) );
349 #else
350 *(uint32_t *)s = MP4V2_HTONL(i);
351 #endif
352 s[4] = 0;
353 }
354
355 ///////////////////////////////////////////////////////////////////////////////
356
357 }} // namespace mp4v2::impl
358