comparison Input/aac/libmp4v2/mp4atom.cpp @ 16:6a86fdd4dea4 trunk

[svn] Replacement libmp4v2.
author nenolod
date Mon, 24 Oct 2005 15:33:32 -0700
parents
children
comparison
equal deleted inserted replaced
15:9780c2671a62 16:6a86fdd4dea4
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':
101 if (ATOMID(type) == ATOMID("elst")) {
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");
127 } else if (ATOMID(type) == ATOMID("href")) {
128 pAtom = new MP4HrefAtom();
129 }
130 break;
131 case 'i':
132 if (ATOMID(type) == ATOMID("ipir")) {
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':
144 if (ATOMID(type) == ATOMID("mdhd")) {
145 pAtom = new MP4MdhdAtom();
146 } else if (ATOMID(type) == ATOMID("mvhd")) {
147 pAtom = new MP4MvhdAtom();
148 } else if (ATOMID(type) == ATOMID("mdat")) {
149 pAtom = new MP4MdatAtom();
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':
163 if (ATOMID(type) == ATOMID("name")) { // iTunes
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':
203 if (ATOMID(type) == ATOMID("tkhd")) {
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) {
245 pAtom = new MP4StandardAtom(type);
246 // unknown type is set by StandardAtom type
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(),
290 printf("ReadAtom: pos = 0x%llx\n", pos));
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(),
318 printf("ReadAtom: type = \"%s\" data-size = %llu (0x%llx) hdr %u\n",
319 type, dataSize, dataSize, hdrSize));
320
321 if (pos + hdrSize + dataSize > pParentAtom->GetEnd()) {
322 VERBOSE_ERROR(pFile->GetVerbosity(),
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()));
327 VERBOSE_READ(pFile->GetVerbosity(),
328 printf("parent %s (%llu) pos %llu hdr %d data %llu sum %llu\n",
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(),
395 printf("Warning: %s atom size %llu is suspect\n",
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(),
413 printf("Skip: %llu bytes\n", m_end - m_pFile->GetPosition()));
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(),
549 printf("ReadProperties: insufficient data for property: %s pos 0x%llx atom end 0x%llx\n",
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(),
591 printf("Error: In %s atom, extra %lld bytes at end of atom\n",
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);
703 VERBOSE_WRITE(GetVerbosity(),
704 printf("end: type %s %llu %llu size %llu\n", m_type,
705 m_start, m_end,
706 m_size));
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