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
Base64ToBinary(const char * pData,uint32_t decodeSize,uint32_t * pDataSize)198 uint8_t *Base64ToBinary (const char *pData, uint32_t decodeSize, uint32_t *pDataSize)
199 {
200 uint8_t *ret;
201 uint32_t size, ix, groups;
202 if (pData == NULL || decodeSize == 0 || pDataSize == NULL)
203 return NULL;
204
205 if ((decodeSize % 4) != 0) {
206 // must be multiples of 4 characters
207 return NULL;
208 }
209 size = (decodeSize * 3) / 4;
210 groups = decodeSize / 4;
211 ret = (uint8_t *)MP4Calloc(size);
212 if (ret == NULL) return NULL;
213 for (ix = 0; ix < groups; ix++) {
214 uint8_t value[4];
215 for (uint8_t jx = 0; jx < 4; jx++) {
216 if (pData[jx] == '=') {
217 if (ix != (groups - 1)) {
218 free(ret);
219 return NULL;
220 }
221 size--;
222 value[jx] = 0;
223 } else if (convertBase64(pData[jx], &value[jx]) == false) {
224 free(ret);
225 return NULL;
226 }
227 }
228 ret[(ix * 3)] = value[0] << 2 | ((value[1] >> 4) & 0x3);
229 ret[(ix * 3) + 1] = (value[1] << 4) | (value[2] >> 2 & 0xf);
230 ret[(ix * 3) + 2] = ((value[2] & 0x3) << 6) | value[3];
231 pData += 4;
232 }
233 *pDataSize = size;
234 return ret;
235 }
236
237 // log2 of value, rounded up
ilog2(uint64_t value)238 static uint8_t ilog2(uint64_t value)
239 {
240 uint64_t powerOf2 = 1;
241 for (uint8_t i = 0; i < 64; i++) {
242 if (value <= powerOf2) {
243 return i;
244 }
245 powerOf2 <<= 1;
246 }
247 return 64;
248 }
249
MP4ConvertTime(uint64_t t,uint32_t oldTimeScale,uint32_t newTimeScale)250 uint64_t MP4ConvertTime(uint64_t t,
251 uint32_t oldTimeScale, uint32_t newTimeScale)
252 {
253 // avoid float point exception
254 if (oldTimeScale == 0) {
255 throw new Exception("division by zero", __FILE__, __LINE__, __FUNCTION__ );
256 }
257
258 if (oldTimeScale == newTimeScale) return t;
259
260 // check if we can safely use integer operations
261 if (ilog2(t) + ilog2(newTimeScale) <= 64) {
262 return (t * newTimeScale) / oldTimeScale;
263 }
264
265 // final resort is to use floating point
266 double d = (double)newTimeScale;
267 d *= double(t);
268 d /= (double)oldTimeScale;
269 d += 0.5; // round up.
270
271 return (uint64_t)d;
272 }
273
MP4NormalizeTrackType(const char * type)274 const char* MP4NormalizeTrackType (const char* type)
275 {
276 if (!strcasecmp(type, "vide")
277 || !strcasecmp(type, "video")
278 || !strcasecmp(type, "mp4v")
279 || !strcasecmp(type, "avc1")
280 || !strcasecmp(type, "s263") // 3GPP H.263
281 || !strcasecmp(type, "encv")) {
282 return MP4_VIDEO_TRACK_TYPE;
283 }
284
285 if (!strcasecmp(type, "soun")
286 || !strcasecmp(type, "sound")
287 || !strcasecmp(type, "audio")
288 || !strcasecmp(type, "enca")
289 || !strcasecmp(type, "samr") // 3GPP AMR
290 || !strcasecmp(type, "sawb") // 3GPP AMR/WB
291 || !strcasecmp(type, "mp4a")) {
292 return MP4_AUDIO_TRACK_TYPE;
293 }
294
295 if (!strcasecmp(type, "sdsm")
296 || !strcasecmp(type, "scene")
297 || !strcasecmp(type, "bifs")) {
298 return MP4_SCENE_TRACK_TYPE;
299 }
300
301 if (!strcasecmp(type, "odsm")
302 || !strcasecmp(type, "od")) {
303 return MP4_OD_TRACK_TYPE;
304 }
305 if (strcasecmp(type, "cntl") == 0) {
306 return MP4_CNTL_TRACK_TYPE;
307 }
308
309 log.verbose1f("Attempt to normalize %s did not match",type);
310
311 return type;
312 }
313
MP4GetAbsTimestamp()314 MP4Timestamp MP4GetAbsTimestamp() {
315 /* MP4 epoch is midnight, January 1, 1904
316 * offset from midnight, January 1, 1970 is 2082844800 seconds
317 * 208284480 is (((1970 - 1904) * 365) + 17) * 24 * 60 * 60
318 */
319 return time::getLocalTimeSeconds() + 2082844800;
320 }
321
322 ///////////////////////////////////////////////////////////////////////////////
323
STRTOINT32(const char * s)324 uint32_t STRTOINT32( const char* s )
325 {
326 #if defined( MP4V2_INTSTRING_ALIGNMENT )
327 // it seems ARM integer instructions require 4-byte alignment so we
328 // manually copy string-data into the integer before performing ops
329 uint32_t tmp;
330 memcpy( &tmp, s, sizeof(tmp) );
331 return MP4V2_NTOHL( tmp );
332 #else
333 return MP4V2_NTOHL(*(uint32_t *)s);
334 #endif
335 }
336
INT32TOSTR(uint32_t i,char * s)337 void INT32TOSTR( uint32_t i, char* s )
338 {
339 #if defined( MP4V2_INTSTRING_ALIGNMENT )
340 // it seems ARM integer instructions require 4-byte alignment so we
341 // manually copy string-data into the integer before performing ops
342 uint32_t tmp = MP4V2_HTONL( i );
343 memcpy( s, &tmp, sizeof(tmp) );
344 #else
345 *(uint32_t *)s = MP4V2_HTONL(i);
346 #endif
347 s[4] = 0;
348 }
349
350 ///////////////////////////////////////////////////////////////////////////////
351
352 }} // namespace mp4v2::impl
353