Mercurial > audlegacy
annotate Plugins/Input/aac/libmp4v2/mp4atom.cpp @ 201:f2dc045d2327 trunk
[svn] libmp4v2 goes back to the future
author | chainsaw |
---|---|
date | Thu, 17 Nov 2005 14:01:18 -0800 |
parents | 0a2ad94e8607 |
children |
rev | line source |
---|---|
61 | 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 - 2004. All Rights Reserved. | |
17 * | |
18 * 3GPP features implementation is based on 3GPP's TS26.234-v5.60, | |
19 * and was contributed by Ximpo Group Ltd. | |
20 * | |
21 * Portions created by Ximpo Group Ltd. are | |
22 * Copyright (C) Ximpo Group Ltd. 2003, 2004. All Rights Reserved. | |
23 * | |
24 * Contributor(s): | |
25 * Dave Mackie dmackie@cisco.com | |
26 * Alix Marchandise-Franquet alix@cisco.com | |
27 * Ximpo Group Ltd. mp4v2@ximpo.com | |
28 */ | |
29 | |
30 #include "mp4common.h" | |
31 #include "atoms.h" | |
32 | |
33 MP4AtomInfo::MP4AtomInfo(const char* name, bool mandatory, bool onlyOne) | |
34 { | |
35 m_name = name; | |
36 m_mandatory = mandatory; | |
37 m_onlyOne = onlyOne; | |
38 m_count = 0; | |
39 } | |
40 | |
41 MP4Atom::MP4Atom(const char* type) | |
42 { | |
43 SetType(type); | |
44 m_unknownType = FALSE; | |
45 m_pFile = NULL; | |
46 m_start = 0; | |
47 m_end = 0; | |
48 m_size = 0; | |
49 m_pParentAtom = NULL; | |
50 m_depth = 0xFF; | |
51 } | |
52 | |
53 MP4Atom::~MP4Atom() | |
54 { | |
55 u_int32_t i; | |
56 | |
57 for (i = 0; i < m_pProperties.Size(); i++) { | |
58 delete m_pProperties[i]; | |
59 } | |
60 for (i = 0; i < m_pChildAtomInfos.Size(); i++) { | |
61 delete m_pChildAtomInfos[i]; | |
62 } | |
63 for (i = 0; i < m_pChildAtoms.Size(); i++) { | |
64 delete m_pChildAtoms[i]; | |
65 } | |
66 } | |
67 | |
68 MP4Atom* MP4Atom::CreateAtom(const char* type) | |
69 { | |
70 MP4Atom* pAtom = NULL; | |
71 | |
72 if (type == NULL) { | |
73 pAtom = new MP4RootAtom(); | |
74 } else { | |
75 switch((uint8_t)type[0]) { | |
76 case 'a': | |
77 if (ATOMID(type) == ATOMID("avc1")) { | |
78 pAtom = new MP4Avc1Atom(); | |
79 } else if (ATOMID(type) == ATOMID("avcC")) { | |
80 pAtom = new MP4AvcCAtom(); | |
81 } else if (ATOMID(type) == ATOMID("alis")) { | |
82 pAtom = new MP4UrlAtom("alis"); | |
83 } else if (ATOMID(type) == ATOMID("alaw")) { | |
84 pAtom = new MP4SoundAtom("alaw"); | |
85 } | |
86 break; | |
87 case 'd': | |
88 if (ATOMID(type) == ATOMID("d263")) { | |
89 pAtom = new MP4D263Atom(); | |
90 } else if (ATOMID(type) == ATOMID("damr")) { | |
91 pAtom = new MP4DamrAtom(); | |
92 } else if (ATOMID(type) == ATOMID("dref")) { | |
93 pAtom = new MP4DrefAtom(); | |
94 } else if (ATOMID(type) == ATOMID("dpnd")) { | |
95 pAtom = new MP4TrefTypeAtom(type); | |
96 } else if (ATOMID(type) == ATOMID("data")) { /* Apple iTunes */ | |
97 pAtom = new MP4DataAtom(); | |
98 } | |
99 break; | |
100 case 'e': | |
201 | 101 if (ATOMID(type) == ATOMID("elst")) { |
61 | 102 pAtom = new MP4ElstAtom(); |
103 } else if (ATOMID(type) == ATOMID("enca")) { | |
104 pAtom = new MP4EncaAtom(); | |
105 } else if (ATOMID(type) == ATOMID("encv")) { | |
106 pAtom = new MP4EncvAtom(); | |
107 } | |
108 break; | |
109 case 'f': | |
110 if (ATOMID(type) == ATOMID("free")) { | |
111 pAtom = new MP4FreeAtom(); | |
112 } else if (ATOMID(type) == ATOMID("ftyp")) { | |
113 pAtom = new MP4FtypAtom(); | |
114 } | |
115 break; | |
116 case 'h': | |
117 if (ATOMID(type) == ATOMID("hdlr")) { | |
118 pAtom = new MP4HdlrAtom(); | |
119 } else if (ATOMID(type) == ATOMID("hint")) { | |
120 pAtom = new MP4TrefTypeAtom(type); | |
121 } else if (ATOMID(type) == ATOMID("hnti")) { | |
122 pAtom = new MP4HntiAtom(); | |
123 } else if (ATOMID(type) == ATOMID("hinf")) { | |
124 pAtom = new MP4HinfAtom(); | |
125 } else if (ATOMID(type) == ATOMID("h263")) { | |
126 pAtom = new MP4VideoAtom("h263"); | |
201 | 127 } else if (ATOMID(type) == ATOMID("href")) { |
128 pAtom = new MP4HrefAtom(); | |
61 | 129 } |
130 break; | |
131 case 'i': | |
201 | 132 if (ATOMID(type) == ATOMID("ipir")) { |
61 | 133 pAtom = new MP4TrefTypeAtom(type); |
134 } else if (ATOMID(type) == ATOMID("ima4")) { | |
135 pAtom = new MP4SoundAtom("ima4"); | |
136 } | |
137 break; | |
138 case 'j': | |
139 if (ATOMID(type) == ATOMID("jpeg")) { | |
140 pAtom = new MP4VideoAtom("jpeg"); | |
141 } | |
142 break; | |
143 case 'm': | |
201 | 144 if (ATOMID(type) == ATOMID("mdhd")) { |
61 | 145 pAtom = new MP4MdhdAtom(); |
201 | 146 } else if (ATOMID(type) == ATOMID("mvhd")) { |
147 pAtom = new MP4MvhdAtom(); | |
199
0a2ad94e8607
[svn] Synced with bmp-mp4. Build system is fragile, but should work now.
chainsaw
parents:
61
diff
changeset
|
148 } else if (ATOMID(type) == ATOMID("mdat")) { |
0a2ad94e8607
[svn] Synced with bmp-mp4. Build system is fragile, but should work now.
chainsaw
parents:
61
diff
changeset
|
149 pAtom = new MP4MdatAtom(); |
61 | 150 } else if (ATOMID(type) == ATOMID("mpod")) { |
151 pAtom = new MP4TrefTypeAtom(type); | |
152 } else if (ATOMID(type) == ATOMID("mp4a")) { | |
153 pAtom = new MP4Mp4aAtom(); | |
154 } else if (ATOMID(type) == ATOMID("mp4s")) { | |
155 pAtom = new MP4Mp4sAtom(); | |
156 } else if (ATOMID(type) == ATOMID("mp4v")) { | |
157 pAtom = new MP4Mp4vAtom(); | |
158 } else if (ATOMID(type) == ATOMID("mean")) { // iTunes | |
159 pAtom = new MP4MeanAtom(); | |
160 } | |
161 break; | |
162 case 'n': | |
201 | 163 if (ATOMID(type) == ATOMID("name")) { // iTunes |
61 | 164 pAtom = new MP4NameAtom(); |
165 } | |
166 break; | |
167 case 'r': | |
168 if (ATOMID(type) == ATOMID("rtp ")) { | |
169 pAtom = new MP4RtpAtom(); | |
170 } else if (ATOMID(type) == ATOMID("raw ")) { | |
171 pAtom = new MP4VideoAtom("raw "); | |
172 } | |
173 break; | |
174 case 's': | |
175 if (ATOMID(type) == ATOMID("s263")) { | |
176 pAtom = new MP4S263Atom(); | |
177 } else if (ATOMID(type) == ATOMID("samr")) { | |
178 pAtom = new MP4AmrAtom("samr"); | |
179 } else if (ATOMID(type) == ATOMID("sawb")) { | |
180 pAtom = new MP4AmrAtom("sawb"); | |
181 } else if (ATOMID(type) == ATOMID("stbl")) { | |
182 pAtom = new MP4StblAtom(); | |
183 } else if (ATOMID(type) == ATOMID("stsd")) { | |
184 pAtom = new MP4StsdAtom(); | |
185 } else if (ATOMID(type) == ATOMID("stsz")) { | |
186 pAtom = new MP4StszAtom(); | |
187 } else if (ATOMID(type) == ATOMID("stsc")) { | |
188 pAtom = new MP4StscAtom(); | |
189 } else if (ATOMID(type) == ATOMID("stdp")) { | |
190 pAtom = new MP4StdpAtom(); | |
191 } else if (ATOMID(type) == ATOMID("sdp ")) { | |
192 pAtom = new MP4SdpAtom(); | |
193 } else if (ATOMID(type) == ATOMID("sync")) { | |
194 pAtom = new MP4TrefTypeAtom(type); | |
195 } else if (ATOMID(type) == ATOMID("skip")) { | |
196 pAtom = new MP4FreeAtom(); | |
197 pAtom->SetType("skip"); | |
198 } else if (ATOMID(type) == ATOMID("sowt")) { | |
199 pAtom = new MP4SoundAtom("sowt"); | |
200 } | |
201 break; | |
202 case 't': | |
201 | 203 if (ATOMID(type) == ATOMID("tkhd")) { |
61 | 204 pAtom = new MP4TkhdAtom(); |
205 } else if (ATOMID(type) == ATOMID("tfhd")) { | |
206 pAtom = new MP4TfhdAtom(); | |
207 } else if (ATOMID(type) == ATOMID("trun")) { | |
208 pAtom = new MP4TrunAtom(); | |
209 } else if (ATOMID(type) == ATOMID("twos")) { | |
210 pAtom = new MP4SoundAtom("twos"); | |
211 } | |
212 break; | |
213 case 'u': | |
214 if (ATOMID(type) == ATOMID("udta")) { | |
215 pAtom = new MP4UdtaAtom(); | |
216 } else if (ATOMID(type) == ATOMID("url ")) { | |
217 pAtom = new MP4UrlAtom(); | |
218 } else if (ATOMID(type) == ATOMID("urn ")) { | |
219 pAtom = new MP4UrnAtom(); | |
220 } else if (ATOMID(type) == ATOMID("ulaw")) { | |
221 pAtom = new MP4SoundAtom("ulaw"); | |
222 } | |
223 break; | |
224 case 'v': | |
225 if (ATOMID(type) == ATOMID("vmhd")) { | |
226 pAtom = new MP4VmhdAtom(); | |
227 } | |
228 break; | |
229 case 'y': | |
230 if (ATOMID(type) == ATOMID("yuv2")) { | |
231 pAtom = new MP4VideoAtom("yuv2"); | |
232 } | |
233 break; | |
234 case 'S': | |
235 if (ATOMID(type) == ATOMID("SVQ3")) { | |
236 pAtom = new MP4VideoAtom("SVQ3"); | |
237 } else if (ATOMID(type) == ATOMID("SMI ")) { | |
238 pAtom = new MP4SmiAtom(); | |
239 } | |
240 break; | |
241 } | |
242 } | |
243 | |
244 if (pAtom == NULL) { | |
201 | 245 pAtom = new MP4StandardAtom(type); |
246 // unknown type is set by StandardAtom type | |
61 | 247 } |
248 | |
249 ASSERT(pAtom); | |
250 return pAtom; | |
251 } | |
252 | |
253 // generate a skeletal self | |
254 | |
255 void MP4Atom::Generate() | |
256 { | |
257 u_int32_t i; | |
258 | |
259 // for all properties | |
260 for (i = 0; i < m_pProperties.Size(); i++) { | |
261 // ask it to self generate | |
262 m_pProperties[i]->Generate(); | |
263 } | |
264 | |
265 // for all mandatory, single child atom types | |
266 for (i = 0; i < m_pChildAtomInfos.Size(); i++) { | |
267 if (m_pChildAtomInfos[i]->m_mandatory | |
268 && m_pChildAtomInfos[i]->m_onlyOne) { | |
269 | |
270 // create the mandatory, single child atom | |
271 MP4Atom* pChildAtom = | |
272 CreateAtom(m_pChildAtomInfos[i]->m_name); | |
273 | |
274 AddChildAtom(pChildAtom); | |
275 | |
276 // and ask it to self generate | |
277 pChildAtom->Generate(); | |
278 } | |
279 } | |
280 } | |
281 | |
282 MP4Atom* MP4Atom::ReadAtom(MP4File* pFile, MP4Atom* pParentAtom) | |
283 { | |
284 u_int8_t hdrSize = 8; | |
285 u_int8_t extendedType[16]; | |
286 | |
287 u_int64_t pos = pFile->GetPosition(); | |
288 | |
289 VERBOSE_READ(pFile->GetVerbosity(), | |
201 | 290 printf("ReadAtom: pos = 0x%llx\n", pos)); |
61 | 291 |
292 u_int64_t dataSize = pFile->ReadUInt32(); | |
293 | |
294 char type[5]; | |
295 pFile->ReadBytes((u_int8_t*)&type[0], 4); | |
296 type[4] = '\0'; | |
297 | |
298 // extended size | |
299 if (dataSize == 1) { | |
300 dataSize = pFile->ReadUInt64(); | |
301 hdrSize += 8; | |
302 } | |
303 | |
304 // extended type | |
305 if (ATOMID(type) == ATOMID("uuid")) { | |
306 pFile->ReadBytes(extendedType, sizeof(extendedType)); | |
307 hdrSize += sizeof(extendedType); | |
308 } | |
309 | |
310 if (dataSize == 0) { | |
311 // extends to EOF | |
312 dataSize = pFile->GetSize() - pos; | |
313 } | |
314 | |
315 dataSize -= hdrSize; | |
316 | |
317 VERBOSE_READ(pFile->GetVerbosity(), | |
201 | 318 printf("ReadAtom: type = \"%s\" data-size = %llu (0x%llx) hdr %u\n", |
319 type, dataSize, dataSize, hdrSize)); | |
61 | 320 |
321 if (pos + hdrSize + dataSize > pParentAtom->GetEnd()) { | |
322 VERBOSE_ERROR(pFile->GetVerbosity(), | |
201 | 323 printf("ReadAtom: invalid atom size, extends outside parent atom - skipping to end of \"%s\" \"%s\" %llu vs %llu\n", |
324 pParentAtom->GetType(), type, | |
325 pos + hdrSize + dataSize, | |
326 pParentAtom->GetEnd())); | |
61 | 327 VERBOSE_READ(pFile->GetVerbosity(), |
201 | 328 printf("parent %s (%llu) pos %llu hdr %d data %llu sum %llu\n", |
61 | 329 pParentAtom->GetType(), |
330 pParentAtom->GetEnd(), | |
331 pos, | |
332 hdrSize, | |
333 dataSize, | |
334 pos + hdrSize + dataSize)); | |
335 #if 0 | |
336 throw new MP4Error("invalid atom size", "ReadAtom"); | |
337 #else | |
338 // skip to end of atom | |
339 dataSize = pParentAtom->GetEnd() - pos - hdrSize; | |
340 #endif | |
341 } | |
342 | |
343 | |
344 MP4Atom* pAtom = CreateAtom(type); | |
345 pAtom->SetFile(pFile); | |
346 pAtom->SetStart(pos); | |
347 pAtom->SetEnd(pos + hdrSize + dataSize); | |
348 pAtom->SetSize(dataSize); | |
349 if (ATOMID(type) == ATOMID("uuid")) { | |
350 pAtom->SetExtendedType(extendedType); | |
351 } | |
352 if (pAtom->IsUnknownType()) { | |
353 if (!IsReasonableType(pAtom->GetType())) { | |
354 VERBOSE_READ(pFile->GetVerbosity(), | |
355 printf("Warning: atom type %s is suspect\n", pAtom->GetType())); | |
356 } else { | |
357 VERBOSE_READ(pFile->GetVerbosity(), | |
358 printf("Info: atom type %s is unknown\n", pAtom->GetType())); | |
359 } | |
360 | |
361 if (dataSize > 0) { | |
362 pAtom->AddProperty( | |
363 new MP4BytesProperty("data", dataSize)); | |
364 } | |
365 } | |
366 | |
367 pAtom->SetParentAtom(pParentAtom); | |
368 | |
369 pAtom->Read(); | |
370 | |
371 return pAtom; | |
372 } | |
373 | |
374 bool MP4Atom::IsReasonableType(const char* type) | |
375 { | |
376 for (u_int8_t i = 0; i < 4; i++) { | |
377 if (isalnum(type[i])) { | |
378 continue; | |
379 } | |
380 if (i == 3 && type[i] == ' ') { | |
381 continue; | |
382 } | |
383 return false; | |
384 } | |
385 return true; | |
386 } | |
387 | |
388 // generic read | |
389 void MP4Atom::Read() | |
390 { | |
391 ASSERT(m_pFile); | |
392 | |
393 if (ATOMID(m_type) != 0 && m_size > 1000000) { | |
394 VERBOSE_READ(GetVerbosity(), | |
201 | 395 printf("Warning: %s atom size %llu is suspect\n", |
61 | 396 m_type, m_size)); |
397 } | |
398 | |
399 ReadProperties(); | |
400 | |
401 // read child atoms, if we expect there to be some | |
402 if (m_pChildAtomInfos.Size() > 0) { | |
403 ReadChildAtoms(); | |
404 } | |
405 | |
406 Skip(); // to end of atom | |
407 } | |
408 | |
409 void MP4Atom::Skip() | |
410 { | |
411 if (m_pFile->GetPosition() != m_end) { | |
412 VERBOSE_READ(m_pFile->GetVerbosity(), | |
201 | 413 printf("Skip: %llu bytes\n", m_end - m_pFile->GetPosition())); |
61 | 414 } |
415 m_pFile->SetPosition(m_end); | |
416 } | |
417 | |
418 MP4Atom* MP4Atom::FindAtom(const char* name) | |
419 { | |
420 if (!IsMe(name)) { | |
421 return NULL; | |
422 } | |
423 | |
424 if (!IsRootAtom()) { | |
425 VERBOSE_FIND(m_pFile->GetVerbosity(), | |
426 printf("FindAtom: matched %s\n", name)); | |
427 | |
428 name = MP4NameAfterFirst(name); | |
429 | |
430 // I'm the sought after atom | |
431 if (name == NULL) { | |
432 return this; | |
433 } | |
434 } | |
435 | |
436 // else it's one of my children | |
437 return FindChildAtom(name); | |
438 } | |
439 | |
440 bool MP4Atom::FindProperty(const char *name, | |
441 MP4Property** ppProperty, u_int32_t* pIndex) | |
442 { | |
443 if (!IsMe(name)) { | |
444 return false; | |
445 } | |
446 | |
447 if (!IsRootAtom()) { | |
448 VERBOSE_FIND(m_pFile->GetVerbosity(), | |
449 printf("FindProperty: matched %s\n", name)); | |
450 | |
451 name = MP4NameAfterFirst(name); | |
452 | |
453 // no property name given | |
454 if (name == NULL) { | |
455 return false; | |
456 } | |
457 } | |
458 | |
459 return FindContainedProperty(name, ppProperty, pIndex); | |
460 } | |
461 | |
462 bool MP4Atom::IsMe(const char* name) | |
463 { | |
464 if (name == NULL) { | |
465 return false; | |
466 } | |
467 | |
468 // root atom always matches | |
469 if (!strcmp(m_type, "")) { | |
470 return true; | |
471 } | |
472 | |
473 // check if our atom name is specified as the first component | |
474 if (!MP4NameFirstMatches(m_type, name)) { | |
475 return false; | |
476 } | |
477 | |
478 return true; | |
479 } | |
480 | |
481 MP4Atom* MP4Atom::FindChildAtom(const char* name) | |
482 { | |
483 u_int32_t atomIndex = 0; | |
484 | |
485 // get the index if we have one, e.g. moov.trak[2].mdia... | |
486 MP4NameFirstIndex(name, &atomIndex); | |
487 | |
488 // need to get to the index'th child atom of the right type | |
489 for (u_int32_t i = 0; i < m_pChildAtoms.Size(); i++) { | |
490 if (MP4NameFirstMatches(m_pChildAtoms[i]->GetType(), name)) { | |
491 if (atomIndex == 0) { | |
492 // this is the one, ask it to match | |
493 return m_pChildAtoms[i]->FindAtom(name); | |
494 } | |
495 atomIndex--; | |
496 } | |
497 } | |
498 | |
499 return NULL; | |
500 } | |
501 | |
502 bool MP4Atom::FindContainedProperty(const char *name, | |
503 MP4Property** ppProperty, u_int32_t* pIndex) | |
504 { | |
505 u_int32_t numProperties = m_pProperties.Size(); | |
506 u_int32_t i; | |
507 // check all of our properties | |
508 for (i = 0; i < numProperties; i++) { | |
509 if (m_pProperties[i]->FindProperty(name, ppProperty, pIndex)) { | |
510 return true; | |
511 } | |
512 } | |
513 | |
514 // not one of our properties, | |
515 // presumably one of our children's properties | |
516 // check child atoms... | |
517 | |
518 // check if we have an index, e.g. trak[2].mdia... | |
519 u_int32_t atomIndex = 0; | |
520 MP4NameFirstIndex(name, &atomIndex); | |
521 | |
522 // need to get to the index'th child atom of the right type | |
523 for (i = 0; i < m_pChildAtoms.Size(); i++) { | |
524 if (MP4NameFirstMatches(m_pChildAtoms[i]->GetType(), name)) { | |
525 if (atomIndex == 0) { | |
526 // this is the one, ask it to match | |
527 return m_pChildAtoms[i]->FindProperty(name, ppProperty, pIndex); | |
528 } | |
529 atomIndex--; | |
530 } | |
531 } | |
532 | |
533 VERBOSE_FIND(m_pFile->GetVerbosity(), | |
534 printf("FindProperty: no match for %s\n", name)); | |
535 return false; | |
536 } | |
537 | |
538 void MP4Atom::ReadProperties(u_int32_t startIndex, u_int32_t count) | |
539 { | |
540 u_int32_t numProperties = MIN(count, m_pProperties.Size() - startIndex); | |
541 | |
542 // read any properties of the atom | |
543 for (u_int32_t i = startIndex; i < startIndex + numProperties; i++) { | |
544 | |
545 m_pProperties[i]->Read(m_pFile); | |
546 | |
547 if (m_pFile->GetPosition() > m_end) { | |
548 VERBOSE_READ(GetVerbosity(), | |
201 | 549 printf("ReadProperties: insufficient data for property: %s pos 0x%llx atom end 0x%llx\n", |
61 | 550 m_pProperties[i]->GetName(), |
551 m_pFile->GetPosition(), m_end)); | |
552 | |
553 throw new MP4Error("atom is too small", "Atom ReadProperties"); | |
554 } | |
555 | |
556 if (m_pProperties[i]->GetType() == TableProperty) { | |
557 VERBOSE_READ_TABLE(GetVerbosity(), | |
558 printf("Read: "); m_pProperties[i]->Dump(stdout, 0, true)); | |
559 } else if (m_pProperties[i]->GetType() != DescriptorProperty) { | |
560 VERBOSE_READ(GetVerbosity(), | |
561 printf("Read: "); m_pProperties[i]->Dump(stdout, 0, true)); | |
562 } | |
563 } | |
564 } | |
565 | |
566 void MP4Atom::ReadChildAtoms() | |
567 { | |
568 bool this_is_udta = ATOMID(m_type) == ATOMID("udta"); | |
569 | |
570 VERBOSE_READ(GetVerbosity(), | |
571 printf("ReadChildAtoms: of %s\n", m_type[0] ? m_type : "root")); | |
572 for (u_int64_t position = m_pFile->GetPosition(); | |
573 position < m_end; | |
574 position = m_pFile->GetPosition()) { | |
575 // make sure that we have enough to read at least 8 bytes | |
576 // size and type. | |
577 if (m_end - position < 2 * sizeof(uint32_t)) { | |
578 // if we're reading udta, it's okay to have 4 bytes of 0 | |
579 if (this_is_udta && | |
580 m_end - position == sizeof(uint32_t)) { | |
581 u_int32_t mbz = m_pFile->ReadUInt32(); | |
582 if (mbz != 0) { | |
583 VERBOSE_WARNING(GetVerbosity(), | |
584 printf("Error: In udta atom, end value is not zero %x\n", | |
585 mbz)); | |
586 } | |
587 continue; | |
588 } | |
589 // otherwise, output a warning, but don't care | |
590 VERBOSE_WARNING(GetVerbosity(), | |
201 | 591 printf("Error: In %s atom, extra %lld bytes at end of atom\n", |
61 | 592 m_type, (m_end - position))); |
593 for (uint64_t ix = 0; ix < m_end - position; ix++) { | |
594 m_pFile->ReadUInt8(); | |
595 } | |
596 continue; | |
597 } | |
598 MP4Atom* pChildAtom = MP4Atom::ReadAtom(m_pFile, this); | |
599 | |
600 AddChildAtom(pChildAtom); | |
601 | |
602 MP4AtomInfo* pChildAtomInfo = FindAtomInfo(pChildAtom->GetType()); | |
603 | |
604 // if child atom is of known type | |
605 // but not expected here print warning | |
606 if (pChildAtomInfo == NULL && !pChildAtom->IsUnknownType()) { | |
607 VERBOSE_READ(GetVerbosity(), | |
608 printf("Warning: In atom %s unexpected child atom %s\n", | |
609 GetType(), pChildAtom->GetType())); | |
610 } | |
611 | |
612 // if child atoms should have just one instance | |
613 // and this is more than one, print warning | |
614 if (pChildAtomInfo) { | |
615 pChildAtomInfo->m_count++; | |
616 | |
617 if (pChildAtomInfo->m_onlyOne && pChildAtomInfo->m_count > 1) { | |
618 VERBOSE_READ(GetVerbosity(), | |
619 printf("Warning: In atom %s multiple child atoms %s\n", | |
620 GetType(), pChildAtom->GetType())); | |
621 } | |
622 } | |
623 | |
624 } | |
625 | |
626 // if mandatory child atom doesn't exist, print warning | |
627 u_int32_t numAtomInfo = m_pChildAtomInfos.Size(); | |
628 for (u_int32_t i = 0; i < numAtomInfo; i++) { | |
629 if (m_pChildAtomInfos[i]->m_mandatory | |
630 && m_pChildAtomInfos[i]->m_count == 0) { | |
631 VERBOSE_READ(GetVerbosity(), | |
632 printf("Warning: In atom %s missing child atom %s\n", | |
633 GetType(), m_pChildAtomInfos[i]->m_name)); | |
634 } | |
635 } | |
636 | |
637 VERBOSE_READ(GetVerbosity(), | |
638 printf("ReadChildAtoms: finished %s\n", m_type)); | |
639 } | |
640 | |
641 MP4AtomInfo* MP4Atom::FindAtomInfo(const char* name) | |
642 { | |
643 u_int32_t numAtomInfo = m_pChildAtomInfos.Size(); | |
644 for (u_int32_t i = 0; i < numAtomInfo; i++) { | |
645 if (ATOMID(m_pChildAtomInfos[i]->m_name) == ATOMID(name)) { | |
646 return m_pChildAtomInfos[i]; | |
647 } | |
648 } | |
649 return NULL; | |
650 } | |
651 | |
652 // generic write | |
653 void MP4Atom::Write() | |
654 { | |
655 ASSERT(m_pFile); | |
656 | |
657 BeginWrite(); | |
658 | |
659 WriteProperties(); | |
660 | |
661 WriteChildAtoms(); | |
662 | |
663 FinishWrite(); | |
664 } | |
665 | |
666 void MP4Atom::Rewrite() | |
667 { | |
668 ASSERT(m_pFile); | |
669 | |
670 if (!m_end) { | |
671 // This atom hasn't been written yet... | |
672 return; | |
673 } | |
674 | |
675 u_int64_t fPos = m_pFile->GetPosition(); | |
676 m_pFile->SetPosition(GetStart()); | |
677 Write(); | |
678 m_pFile->SetPosition(fPos); | |
679 } | |
680 | |
681 void MP4Atom::BeginWrite(bool use64) | |
682 { | |
683 m_start = m_pFile->GetPosition(); | |
684 //use64 = m_pFile->Use64Bits(); | |
685 if (use64) { | |
686 m_pFile->WriteUInt32(1); | |
687 } else { | |
688 m_pFile->WriteUInt32(0); | |
689 } | |
690 m_pFile->WriteBytes((u_int8_t*)&m_type[0], 4); | |
691 if (use64) { | |
692 m_pFile->WriteUInt64(0); | |
693 } | |
694 if (ATOMID(m_type) == ATOMID("uuid")) { | |
695 m_pFile->WriteBytes(m_extendedType, sizeof(m_extendedType)); | |
696 } | |
697 } | |
698 | |
699 void MP4Atom::FinishWrite(bool use64) | |
700 { | |
701 m_end = m_pFile->GetPosition(); | |
702 m_size = (m_end - m_start); | |
201 | 703 VERBOSE_WRITE(GetVerbosity(), |
704 printf("end: type %s %llu %llu size %llu\n", m_type, | |
705 m_start, m_end, | |
706 m_size)); | |
61 | 707 //use64 = m_pFile->Use64Bits(); |
708 if (use64) { | |
709 m_pFile->SetPosition(m_start + 8); | |
710 m_pFile->WriteUInt64(m_size); | |
711 } else { | |
712 ASSERT(m_size <= (u_int64_t)0xFFFFFFFF); | |
713 m_pFile->SetPosition(m_start); | |
714 m_pFile->WriteUInt32(m_size); | |
715 } | |
716 m_pFile->SetPosition(m_end); | |
717 | |
718 // adjust size to just reflect data portion of atom | |
719 m_size -= (use64 ? 16 : 8); | |
720 if (ATOMID(m_type) == ATOMID("uuid")) { | |
721 m_size -= sizeof(m_extendedType); | |
722 } | |
723 } | |
724 | |
725 void MP4Atom::WriteProperties(u_int32_t startIndex, u_int32_t count) | |
726 { | |
727 u_int32_t numProperties = MIN(count, m_pProperties.Size() - startIndex); | |
728 | |
729 VERBOSE_WRITE(GetVerbosity(), | |
730 printf("Write: type %s\n", m_type)); | |
731 | |
732 for (u_int32_t i = startIndex; i < startIndex + numProperties; i++) { | |
733 m_pProperties[i]->Write(m_pFile); | |
734 | |
735 if (m_pProperties[i]->GetType() == TableProperty) { | |
736 VERBOSE_WRITE_TABLE(GetVerbosity(), | |
737 printf("Write: "); m_pProperties[i]->Dump(stdout, 0, false)); | |
738 } else { | |
739 VERBOSE_WRITE(GetVerbosity(), | |
740 printf("Write: "); m_pProperties[i]->Dump(stdout, 0, false)); | |
741 } | |
742 } | |
743 } | |
744 | |
745 void MP4Atom::WriteChildAtoms() | |
746 { | |
747 u_int32_t size = m_pChildAtoms.Size(); | |
748 for (u_int32_t i = 0; i < size; i++) { | |
749 m_pChildAtoms[i]->Write(); | |
750 } | |
751 | |
752 VERBOSE_WRITE(GetVerbosity(), | |
753 printf("Write: finished %s\n", m_type)); | |
754 } | |
755 | |
756 void MP4Atom::AddProperty(MP4Property* pProperty) | |
757 { | |
758 ASSERT(pProperty); | |
759 m_pProperties.Add(pProperty); | |
760 pProperty->SetParentAtom(this); | |
761 } | |
762 | |
763 void MP4Atom::AddVersionAndFlags() | |
764 { | |
765 AddProperty(new MP4Integer8Property("version")); | |
766 AddProperty(new MP4Integer24Property("flags")); | |
767 } | |
768 | |
769 void MP4Atom::AddReserved(char* name, u_int32_t size) | |
770 { | |
771 MP4BytesProperty* pReserved = new MP4BytesProperty(name, size); | |
772 pReserved->SetReadOnly(); | |
773 AddProperty(pReserved); | |
774 } | |
775 | |
776 void MP4Atom::ExpectChildAtom(const char* name, bool mandatory, bool onlyOne) | |
777 { | |
778 m_pChildAtomInfos.Add(new MP4AtomInfo(name, mandatory, onlyOne)); | |
779 } | |
780 | |
781 u_int8_t MP4Atom::GetVersion() | |
782 { | |
783 if (strcmp("version", m_pProperties[0]->GetName())) { | |
784 return 0; | |
785 } | |
786 return ((MP4Integer8Property*)m_pProperties[0])->GetValue(); | |
787 } | |
788 | |
789 void MP4Atom::SetVersion(u_int8_t version) | |
790 { | |
791 if (strcmp("version", m_pProperties[0]->GetName())) { | |
792 return; | |
793 } | |
794 ((MP4Integer8Property*)m_pProperties[0])->SetValue(version); | |
795 } | |
796 | |
797 u_int32_t MP4Atom::GetFlags() | |
798 { | |
799 if (strcmp("flags", m_pProperties[1]->GetName())) { | |
800 return 0; | |
801 } | |
802 return ((MP4Integer24Property*)m_pProperties[1])->GetValue(); | |
803 } | |
804 | |
805 void MP4Atom::SetFlags(u_int32_t flags) | |
806 { | |
807 if (strcmp("flags", m_pProperties[1]->GetName())) { | |
808 return; | |
809 } | |
810 ((MP4Integer24Property*)m_pProperties[1])->SetValue(flags); | |
811 } | |
812 | |
813 void MP4Atom::Dump(FILE* pFile, u_int8_t indent, bool dumpImplicits) | |
814 { | |
815 if (m_type[0] != '\0') { | |
816 Indent(pFile, indent); | |
817 fprintf(pFile, "type %s\n", m_type); | |
818 fflush(pFile); | |
819 } | |
820 | |
821 u_int32_t i; | |
822 u_int32_t size; | |
823 | |
824 // dump our properties | |
825 size = m_pProperties.Size(); | |
826 for (i = 0; i < size; i++) { | |
827 | |
828 /* skip details of tables unless we're told to be verbose */ | |
829 if (m_pProperties[i]->GetType() == TableProperty | |
830 && !(GetVerbosity() & MP4_DETAILS_TABLE)) { | |
831 Indent(pFile, indent + 1); | |
832 fprintf(pFile, "<table entries suppressed>\n"); | |
833 continue; | |
834 } | |
835 | |
836 m_pProperties[i]->Dump(pFile, indent + 1, dumpImplicits); | |
837 } | |
838 | |
839 // dump our children | |
840 size = m_pChildAtoms.Size(); | |
841 for (i = 0; i < size; i++) { | |
842 m_pChildAtoms[i]->Dump(pFile, indent + 1, dumpImplicits); | |
843 } | |
844 } | |
845 | |
846 u_int32_t MP4Atom::GetVerbosity() | |
847 { | |
848 ASSERT(m_pFile); | |
849 return m_pFile->GetVerbosity(); | |
850 } | |
851 | |
852 u_int8_t MP4Atom::GetDepth() | |
853 { | |
854 if (m_depth < 0xFF) { | |
855 return m_depth; | |
856 } | |
857 | |
858 MP4Atom *pAtom = this; | |
859 m_depth = 0; | |
860 | |
861 while ((pAtom = pAtom->GetParentAtom()) != NULL) { | |
862 m_depth++; | |
863 ASSERT(m_depth < 255); | |
864 } | |
865 return m_depth; | |
866 } | |
867 |