2 * Copyright (c) 2005, David McPaul
5 * Redistribution and use in source and binary forms, with or without modification,
6 * are permitted provided that the following conditions are met:
8 * * Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17 * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
18 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
19 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
21 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
22 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
23 * OF THE POSSIBILITY OF SUCH DAMAGE.
28 #include <SupportKit.h>
29 #include <MediaFormats.h>
32 #include <libs/zlib/zlib.h>
37 #include "MOVParser.h"
40 AtomBase
*getAtom(BPositionIO
*pStream
)
47 aStreamOffset
= pStream
->Position();
50 pStream
->Read(&aAtomSize
,4);
51 aAtomSize
= B_BENDIAN_TO_HOST_INT32(aAtomSize
);
53 pStream
->Read(&aAtomType
,4);
54 aAtomType
= B_BENDIAN_TO_HOST_INT32(aAtomType
);
55 // Check for extended size
57 // Handle extended size
58 pStream
->Read(&aRealAtomSize
,4);
59 aRealAtomSize
= B_BENDIAN_TO_HOST_INT64(aRealAtomSize
);
61 aRealAtomSize
= aAtomSize
;
64 if (aAtomType
== uint32('moov')) {
65 return new MOOVAtom(pStream
, aStreamOffset
, aAtomType
, aRealAtomSize
);
68 if (aAtomType
== uint32('mvhd')) {
69 return new MVHDAtom(pStream
, aStreamOffset
, aAtomType
, aRealAtomSize
);
72 if (aAtomType
== uint32('trak')) {
73 return new TRAKAtom(pStream
, aStreamOffset
, aAtomType
, aRealAtomSize
);
76 if (aAtomType
== uint32('tkhd')) {
77 return new TKHDAtom(pStream
, aStreamOffset
, aAtomType
, aRealAtomSize
);
80 if (aAtomType
== uint32('free')) {
81 return new FREEAtom(pStream
, aStreamOffset
, aAtomType
, aRealAtomSize
);
84 if (aAtomType
== uint32('skip')) {
85 return new SKIPAtom(pStream
, aStreamOffset
, aAtomType
, aRealAtomSize
);
88 if (aAtomType
== uint32('wide')) {
89 return new WIDEAtom(pStream
, aStreamOffset
, aAtomType
, aRealAtomSize
);
92 if (aAtomType
== uint32('mdat')) {
93 return new MDATAtom(pStream
, aStreamOffset
, aAtomType
, aRealAtomSize
);
96 if (aAtomType
== uint32('mdia')) {
97 return new MDIAAtom(pStream
, aStreamOffset
, aAtomType
, aRealAtomSize
);
100 if (aAtomType
== uint32('mdhd')) {
101 return new MDHDAtom(pStream
, aStreamOffset
, aAtomType
, aRealAtomSize
);
104 if (aAtomType
== uint32('hdlr')) {
105 return new HDLRAtom(pStream
, aStreamOffset
, aAtomType
, aRealAtomSize
);
108 if (aAtomType
== uint32('minf')) {
109 return new MINFAtom(pStream
, aStreamOffset
, aAtomType
, aRealAtomSize
);
112 if (aAtomType
== uint32('vmhd')) {
113 return new VMHDAtom(pStream
, aStreamOffset
, aAtomType
, aRealAtomSize
);
116 if (aAtomType
== uint32('smhd')) {
117 return new SMHDAtom(pStream
, aStreamOffset
, aAtomType
, aRealAtomSize
);
120 if (aAtomType
== uint32('dinf')) {
121 return new DINFAtom(pStream
, aStreamOffset
, aAtomType
, aRealAtomSize
);
124 if (aAtomType
== uint32('stbl')) {
125 return new STBLAtom(pStream
, aStreamOffset
, aAtomType
, aRealAtomSize
);
128 if (aAtomType
== uint32('stsd')) {
129 return new STSDAtom(pStream
, aStreamOffset
, aAtomType
, aRealAtomSize
);
132 if (aAtomType
== uint32('tmcd')) {
133 return new TMCDAtom(pStream
, aStreamOffset
, aAtomType
, aRealAtomSize
);
136 if (aAtomType
== uint32('wave')) {
137 return new WAVEAtom(pStream
, aStreamOffset
, aAtomType
, aRealAtomSize
);
140 if (aAtomType
== uint32('stts')) {
141 return new STTSAtom(pStream
, aStreamOffset
, aAtomType
, aRealAtomSize
);
144 if (aAtomType
== uint32('pnot')) {
145 return new PNOTAtom(pStream
, aStreamOffset
, aAtomType
, aRealAtomSize
);
148 if (aAtomType
== uint32('stsc')) {
149 return new STSCAtom(pStream
, aStreamOffset
, aAtomType
, aRealAtomSize
);
152 if (aAtomType
== uint32('stco')) {
153 return new STCOAtom(pStream
, aStreamOffset
, aAtomType
, aRealAtomSize
);
156 if (aAtomType
== uint32('stss')) {
157 return new STSSAtom(pStream
, aStreamOffset
, aAtomType
, aRealAtomSize
);
160 if (aAtomType
== uint32('stsz')) {
161 return new STSZAtom(pStream
, aStreamOffset
, aAtomType
, aRealAtomSize
);
164 if (aAtomType
== uint32('cmov')) {
165 return new CMOVAtom(pStream
, aStreamOffset
, aAtomType
, aRealAtomSize
);
168 if (aAtomType
== uint32('dcom')) {
169 return new DCOMAtom(pStream
, aStreamOffset
, aAtomType
, aRealAtomSize
);
172 if (aAtomType
== uint32('cmvd')) {
173 return new CMVDAtom(pStream
, aStreamOffset
, aAtomType
, aRealAtomSize
);
176 if (aAtomType
== uint32('esds')) {
177 return new ESDSAtom(pStream
, aStreamOffset
, aAtomType
, aRealAtomSize
);
180 if (aAtomType
== uint32('avcC')) {
181 return new ESDSAtom(pStream
, aStreamOffset
, aAtomType
, aRealAtomSize
);
184 if (aAtomType
== uint32('ftyp')) {
185 return new FTYPAtom(pStream
, aStreamOffset
, aAtomType
, aRealAtomSize
);
188 return new AtomBase(pStream
, aStreamOffset
, aAtomType
, aRealAtomSize
);
192 MOOVAtom::MOOVAtom(BPositionIO
*pStream
, off_t pstreamOffset
, uint32 patomType
, uint64 patomSize
) : AtomContainer(pStream
, pstreamOffset
, patomType
, patomSize
)
197 MOOVAtom::~MOOVAtom()
202 void MOOVAtom::OnProcessMetaData()
206 char *MOOVAtom::OnGetAtomName()
208 return "Quicktime Movie";
211 CMOVAtom::CMOVAtom(BPositionIO
*pStream
, off_t pstreamOffset
, uint32 patomType
, uint64 patomSize
) : AtomContainer(pStream
, pstreamOffset
, patomType
, patomSize
)
213 theUncompressedStream
= NULL
;
216 CMOVAtom::~CMOVAtom()
220 BPositionIO
*CMOVAtom::OnGetStream()
222 // Use the decompressed stream instead of file stream
223 if (theUncompressedStream
) {
224 return theUncompressedStream
;
230 void CMOVAtom::OnProcessMetaData()
232 BMallocIO
*theUncompressedData
;
234 CMVDAtom
*aCMVDAtom
= NULL
;
235 uint32 compressionID
= 0;
236 uint64 descBytesLeft
;
239 descBytesLeft
= getAtomSize();
241 // Check for Compression Type
242 while (descBytesLeft
> 0) {
243 AtomBase
*aAtomBase
= getAtom(theStream
);
245 aAtomBase
->OnProcessMetaData();
246 printf("%s [%Ld]\n",aAtomBase
->getAtomName(),aAtomBase
->getAtomSize());
248 if (aAtomBase
->getAtomSize() > 0) {
249 descBytesLeft
= descBytesLeft
- aAtomBase
->getAtomSize();
251 printf("Invalid Atom found when reading Compressed Headers\n");
255 if (dynamic_cast<DCOMAtom
*>(aAtomBase
)) {
257 compressionID
= dynamic_cast<DCOMAtom
*>(aAtomBase
)->getCompressionID();
260 if (dynamic_cast<CMVDAtom
*>(aAtomBase
)) {
262 aCMVDAtom
= dynamic_cast<CMVDAtom
*>(aAtomBase
);
269 if (compressionID
== 'zlib') {
270 Size
= aCMVDAtom
->getUncompressedSize();
272 outBuffer
= (uint8
*)(malloc(Size
));
274 printf("Decompressing %ld bytes to %ld bytes\n",aCMVDAtom
->getBufferSize(),Size
);
275 int result
= uncompress(outBuffer
, &Size
, aCMVDAtom
->getCompressedData(), aCMVDAtom
->getBufferSize());
277 if (result
!= Z_OK
) {
278 printf("Failed to decompress headers uncompress returned ");
281 DEBUGGER("Lack of Memory Error\n");
284 DEBUGGER("Lack of Output buffer space Error\n");
287 DEBUGGER("Input Data is corrupt or not a compressed set Error\n");
292 // Copy uncompressed data into BMAllocIO
293 theUncompressedData
= new BMallocIO();
294 theUncompressedData
->SetSize(Size
);
295 theUncompressedData
->WriteAt(0L,outBuffer
,Size
);
300 // reset position on BMAllocIO
301 theUncompressedData
->Seek(SEEK_SET
,0L);
303 theUncompressedStream
= theUncompressedData
;
305 // All subsequent reads should use theUncompressedStream
310 void CMOVAtom::OnChildProcessingComplete()
312 // revert back to file stream once all children have finished
313 if (theUncompressedStream
) {
314 delete theUncompressedStream
;
316 theUncompressedStream
= NULL
;
319 char *CMOVAtom::OnGetAtomName()
321 return "Compressed Quicktime Movie";
324 DCOMAtom::DCOMAtom(BPositionIO
*pStream
, off_t pstreamOffset
, uint32 patomType
, uint64 patomSize
) : AtomBase(pStream
, pstreamOffset
, patomType
, patomSize
)
328 DCOMAtom::~DCOMAtom()
332 void DCOMAtom::OnProcessMetaData()
334 Read(&compressionID
);
337 char *DCOMAtom::OnGetAtomName()
339 return "Decompression Atom";
342 CMVDAtom::CMVDAtom(BPositionIO
*pStream
, off_t pstreamOffset
, uint32 patomType
, uint64 patomSize
) : AtomBase(pStream
, pstreamOffset
, patomType
, patomSize
)
345 UncompressedSize
= 0;
349 CMVDAtom::~CMVDAtom()
356 void CMVDAtom::OnProcessMetaData()
358 Read(&UncompressedSize
);
360 if (UncompressedSize
> 0) {
361 BufferSize
= getBytesRemaining();
362 Buffer
= (uint8
*)(malloc(BufferSize
));
363 Read(Buffer
,BufferSize
);
367 char *CMVDAtom::OnGetAtomName()
369 return "Compressed Movie Data";
372 MVHDAtom::MVHDAtom(BPositionIO
*pStream
, off_t pstreamOffset
, uint32 patomType
, uint64 patomSize
) : AtomBase(pStream
, pstreamOffset
, patomType
, patomSize
)
376 MVHDAtom::~MVHDAtom()
380 void MVHDAtom::OnProcessMetaData()
382 Read(&theHeader
.CreationTime
);
383 Read(&theHeader
.ModificationTime
);
384 Read(&theHeader
.TimeScale
);
385 Read(&theHeader
.Duration
);
386 Read(&theHeader
.PreferredRate
);
387 Read(&theHeader
.PreferredVolume
);
388 Read(&theHeader
.PreviewTime
);
389 Read(&theHeader
.PreviewDuration
);
390 Read(&theHeader
.PosterTime
);
391 Read(&theHeader
.SelectionTime
);
392 Read(&theHeader
.SelectionDuration
);
393 Read(&theHeader
.CurrentTime
);
394 Read(&theHeader
.NextTrackID
);
397 char *MVHDAtom::OnGetAtomName()
399 return "Quicktime Movie Header";
402 MVHDAtom
*MOOVAtom::getMVHDAtom()
406 if (theMVHDAtom
== NULL
) {
407 aAtomBase
= GetChildAtom(uint32('mvhd'));
408 theMVHDAtom
= dynamic_cast<MVHDAtom
*>(aAtomBase
);
411 // Assert(theMVHDAtom != NULL,"Movie has no movie header atom");
415 STTSAtom::STTSAtom(BPositionIO
*pStream
, off_t pstreamOffset
, uint32 patomType
, uint64 patomSize
) : AtomBase(pStream
, pstreamOffset
, patomType
, patomSize
)
417 theHeader
.NoEntries
= 0;
422 STTSAtom::~STTSAtom()
424 for (uint32 i
=0;i
<theHeader
.NoEntries
;i
++) {
425 delete theTimeToSampleArray
[i
];
426 theTimeToSampleArray
[i
] = NULL
;
430 void STTSAtom::OnProcessMetaData()
432 TimeToSample
*aTimeToSample
;
434 ReadArrayHeader(&theHeader
);
436 for (uint32 i
=0;i
<theHeader
.NoEntries
;i
++) {
437 aTimeToSample
= new TimeToSample
;
439 Read(&aTimeToSample
->Count
);
440 Read(&aTimeToSample
->Duration
);
442 theTimeToSampleArray
[i
] = aTimeToSample
;
443 SUMDurations
+= (theTimeToSampleArray
[i
]->Duration
* theTimeToSampleArray
[i
]->Count
);
444 SUMCounts
+= theTimeToSampleArray
[i
]->Count
;
448 char *STTSAtom::OnGetAtomName()
450 return "Time to Sample Atom";
453 uint32
STTSAtom::getSampleForTime(uint32 pTime
)
455 // TODO this is too slow. PreCalc when loading this?
458 for (uint32 i
=0;i
<theHeader
.NoEntries
;i
++) {
459 Duration
+= (theTimeToSampleArray
[i
]->Duration
* theTimeToSampleArray
[i
]->Count
);
460 if (Duration
> pTime
) {
468 uint32
STTSAtom::getSampleForFrame(uint32 pFrame
)
470 // Hmm Sample is Frame really, this Atom is more usefull for time->sample calcs
474 STSCAtom::STSCAtom(BPositionIO
*pStream
, off_t pstreamOffset
, uint32 patomType
, uint64 patomSize
) : AtomBase(pStream
, pstreamOffset
, patomType
, patomSize
)
476 theHeader
.NoEntries
= 0;
479 STSCAtom::~STSCAtom()
481 for (uint32 i
=0;i
<theHeader
.NoEntries
;i
++) {
482 delete theSampleToChunkArray
[i
];
483 theSampleToChunkArray
[i
] = NULL
;
487 void STSCAtom::OnProcessMetaData()
489 SampleToChunk
*aSampleToChunk
;
491 ReadArrayHeader(&theHeader
);
493 uint32 TotalPrevSamples
= 0;
495 for (uint32 i
=0;i
<theHeader
.NoEntries
;i
++) {
496 aSampleToChunk
= new SampleToChunk
;
498 Read(&aSampleToChunk
->FirstChunk
);
499 Read(&aSampleToChunk
->SamplesPerChunk
);
500 Read(&aSampleToChunk
->SampleDescriptionID
);
503 TotalPrevSamples
= TotalPrevSamples
+ (aSampleToChunk
->FirstChunk
- theSampleToChunkArray
[i
-1]->FirstChunk
) * theSampleToChunkArray
[i
-1]->SamplesPerChunk
;
504 aSampleToChunk
->TotalPrevSamples
= TotalPrevSamples
;
506 aSampleToChunk
->TotalPrevSamples
= 0;
509 theSampleToChunkArray
[i
] = aSampleToChunk
;
513 char *STSCAtom::OnGetAtomName()
515 return "Sample to Chunk Atom";
518 uint32
STSCAtom::getNoSamplesInChunk(uint32 pChunkID
)
520 for (uint32 i
=0;i
<theHeader
.NoEntries
;i
++) {
521 if (theSampleToChunkArray
[i
]->FirstChunk
> pChunkID
) {
522 return theSampleToChunkArray
[i
-1]->SamplesPerChunk
;
526 return theSampleToChunkArray
[theHeader
.NoEntries
-1]->SamplesPerChunk
;
529 uint32
STSCAtom::getFirstSampleInChunk(uint32 pChunkID
)
533 for (uint32 i
=0;i
<theHeader
.NoEntries
;i
++) {
534 if (theSampleToChunkArray
[i
]->FirstChunk
> pChunkID
) {
535 Diff
= pChunkID
- theSampleToChunkArray
[i
-1]->FirstChunk
;
536 return ((Diff
* theSampleToChunkArray
[i
-1]->SamplesPerChunk
) + theSampleToChunkArray
[i
-1]->TotalPrevSamples
);
540 Diff
= pChunkID
- theSampleToChunkArray
[theHeader
.NoEntries
-1]->FirstChunk
;
541 return ((Diff
* theSampleToChunkArray
[theHeader
.NoEntries
-1]->SamplesPerChunk
) + theSampleToChunkArray
[theHeader
.NoEntries
-1]->TotalPrevSamples
);
544 uint32
STSCAtom::getChunkForSample(uint32 pSample
, uint32
*pOffsetInChunk
)
547 uint32 OffsetInChunk
= 0;
549 for (int32 i
=theHeader
.NoEntries
-1;i
>=0;i
--) {
550 if (pSample
>= theSampleToChunkArray
[i
]->TotalPrevSamples
) {
551 // Found chunk now calculate offset
552 ChunkID
= (pSample
- theSampleToChunkArray
[i
]->TotalPrevSamples
) / theSampleToChunkArray
[i
]->SamplesPerChunk
;
553 ChunkID
+= theSampleToChunkArray
[i
]->FirstChunk
;
555 OffsetInChunk
= (pSample
- theSampleToChunkArray
[i
]->TotalPrevSamples
) % theSampleToChunkArray
[i
]->SamplesPerChunk
;
557 *pOffsetInChunk
= OffsetInChunk
;
563 return theSampleToChunkArray
[theHeader
.NoEntries
-1]->FirstChunk
;
566 STSSAtom::STSSAtom(BPositionIO
*pStream
, off_t pstreamOffset
, uint32 patomType
, uint64 patomSize
) : AtomBase(pStream
, pstreamOffset
, patomType
, patomSize
)
568 theHeader
.NoEntries
= 0;
571 STSSAtom::~STSSAtom()
573 for (uint32 i
=0;i
<theHeader
.NoEntries
;i
++) {
574 delete theSyncSampleArray
[i
];
575 theSyncSampleArray
[i
] = NULL
;
579 void STSSAtom::OnProcessMetaData()
581 SyncSample
*aSyncSample
;
583 ReadArrayHeader(&theHeader
);
585 for (uint32 i
=0;i
<theHeader
.NoEntries
;i
++) {
586 aSyncSample
= new SyncSample
;
588 Read(&aSyncSample
->SyncSampleNo
);
589 theSyncSampleArray
[i
] = aSyncSample
;
593 char *STSSAtom::OnGetAtomName()
595 return "Sync Sample Atom";
598 bool STSSAtom::IsSyncSample(uint32 pSampleNo
)
601 for (uint32 i
=0;i
<theHeader
.NoEntries
;i
++) {
602 if (theSyncSampleArray
[i
]->SyncSampleNo
== pSampleNo
) {
606 if (pSampleNo
> theSyncSampleArray
[i
]->SyncSampleNo
) {
614 STSZAtom::STSZAtom(BPositionIO
*pStream
, off_t pstreamOffset
, uint32 patomType
, uint64 patomSize
) : AtomBase(pStream
, pstreamOffset
, patomType
, patomSize
)
616 theHeader
.NoEntries
= 0;
619 STSZAtom::~STSZAtom()
621 for (uint32 i
=0;i
<theHeader
.NoEntries
;i
++) {
622 delete theSampleSizeArray
[i
];
623 theSampleSizeArray
[i
] = NULL
;
627 void STSZAtom::OnProcessMetaData()
629 SampleSizeEntry
*aSampleSize
;
631 // Just to make things difficult this is not quite a standard array header
632 Read(&theHeader
.Version
);
633 Read(&theHeader
.Flags1
);
634 Read(&theHeader
.Flags2
);
635 Read(&theHeader
.Flags3
);
636 Read(&theHeader
.SampleSize
);
637 Read(&theHeader
.NoEntries
);
639 // If the sample size is constant there is no array and NoEntries seems to contain bad values
640 if (theHeader
.SampleSize
== 0) {
641 for (uint32 i
=0;i
<theHeader
.NoEntries
;i
++) {
642 aSampleSize
= new SampleSizeEntry
;
644 Read(&aSampleSize
->EntrySize
);
645 theSampleSizeArray
[i
] = aSampleSize
;
650 char *STSZAtom::OnGetAtomName()
652 return "Sample Size Atom";
655 uint32
STSZAtom::getSizeForSample(uint32 pSampleNo
)
657 if (theHeader
.SampleSize
> 0) {
658 // All samples are the same size
659 return theHeader
.SampleSize
;
662 // Sample Array indexed by SampleNo
663 return theSampleSizeArray
[pSampleNo
]->EntrySize
;
666 bool STSZAtom::IsSingleSampleSize()
668 return (theHeader
.SampleSize
> 0);
671 STCOAtom::STCOAtom(BPositionIO
*pStream
, off_t pstreamOffset
, uint32 patomType
, uint64 patomSize
) : AtomBase(pStream
, pstreamOffset
, patomType
, patomSize
)
673 theHeader
.NoEntries
= 0;
676 STCOAtom::~STCOAtom()
678 for (uint32 i
=0;i
<theHeader
.NoEntries
;i
++) {
679 delete theChunkToOffsetArray
[i
];
680 theChunkToOffsetArray
[i
] = NULL
;
684 uint64
STCOAtom::OnGetChunkOffset()
690 // Upconvert to uint64
691 return uint64(Offset
);
694 void STCOAtom::OnProcessMetaData()
696 ChunkToOffset
*aChunkToOffset
;
698 ReadArrayHeader(&theHeader
);
700 for (uint32 i
=0;i
<theHeader
.NoEntries
;i
++) {
701 aChunkToOffset
= new ChunkToOffset
;
703 aChunkToOffset
->Offset
= OnGetChunkOffset();
705 theChunkToOffsetArray
[i
] = aChunkToOffset
;
708 PRINT(("Chunk to Offset Array has %ld entries\n",theHeader
.NoEntries
));
711 char *STCOAtom::OnGetAtomName()
713 return "Chunk to Offset Atom";
716 uint64
STCOAtom::getOffsetForChunk(uint32 pChunkID
)
718 // First chunk is first array entry
719 if ((pChunkID
> 0) && (pChunkID
<= theHeader
.NoEntries
)) {
720 return theChunkToOffsetArray
[pChunkID
- 1]->Offset
;
724 char msg
[100]; sprintf(msg
, "Bad Chunk ID %ld / %ld\n", pChunkID
, theHeader
.NoEntries
);
732 ESDSAtom::ESDSAtom(BPositionIO
*pStream
, off_t pstreamOffset
, uint32 patomType
, uint64 patomSize
) : AtomBase(pStream
, pstreamOffset
, patomType
, patomSize
)
737 ESDSAtom::~ESDSAtom()
744 void ESDSAtom::OnProcessMetaData()
746 theVOL
= (uint8
*)(malloc(getBytesRemaining()));
747 Read(theVOL
,getBytesRemaining());
750 uint8
*ESDSAtom::getVOL()
755 char *ESDSAtom::OnGetAtomName()
757 return "Extended Sample Description Atom";
760 STSDAtom::STSDAtom(BPositionIO
*pStream
, off_t pstreamOffset
, uint32 patomType
, uint64 patomSize
) : AtomBase(pStream
, pstreamOffset
, patomType
, patomSize
)
762 theHeader
.NoEntries
= 0;
765 STSDAtom::~STSDAtom()
767 if (getMediaComponentSubType() == 'soun') {
768 for (uint32 i
=0;i
<theHeader
.NoEntries
;i
++) {
769 if (theAudioDescArray
[i
]->theVOL
) {
770 free(theAudioDescArray
[i
]->theVOL
);
771 theAudioDescArray
[i
]->theVOL
= NULL
;
774 delete theAudioDescArray
[i
];
775 theAudioDescArray
[i
] = NULL
;
777 } else if (getMediaComponentSubType() == 'vide') {
778 for (uint32 i
=0;i
<theHeader
.NoEntries
;i
++) {
779 if (theVideoDescArray
[i
]->theVOL
) {
780 free(theVideoDescArray
[i
]->theVOL
);
781 theVideoDescArray
[i
]->theVOL
= NULL
;
784 delete theVideoDescArray
[i
];
785 theVideoDescArray
[i
] = NULL
;
790 uint32
STSDAtom::getMediaComponentSubType()
792 return dynamic_cast<STBLAtom
*>(getParent())->getMediaComponentSubType();
795 void STSDAtom::ReadSoundDescription()
797 uint64 descBytesLeft
;
799 SoundDescriptionV1
*aSoundDescriptionV1
;
801 aSoundDescriptionV1
= new SoundDescriptionV1
;
802 Read(&aSoundDescriptionV1
->basefields
.Size
);
803 Read(&aSoundDescriptionV1
->basefields
.DataFormat
);
804 Read(aSoundDescriptionV1
->basefields
.Reserved
,6);
805 Read(&aSoundDescriptionV1
->basefields
.DataReference
);
807 aSoundDescriptionV1
->VOLSize
= 0;
808 aSoundDescriptionV1
->theVOL
= NULL
;
810 // Read in Audio Sample Data
811 // We place into a V1 description even though it might be a V0 or earlier
813 Read(&aSoundDescriptionV1
->desc
.Version
);
814 Read(&aSoundDescriptionV1
->desc
.Revision
);
815 Read(&aSoundDescriptionV1
->desc
.Vendor
);
816 Read(&aSoundDescriptionV1
->desc
.NoOfChannels
);
817 Read(&aSoundDescriptionV1
->desc
.SampleSize
);
818 Read(&aSoundDescriptionV1
->desc
.CompressionID
);
819 Read(&aSoundDescriptionV1
->desc
.PacketSize
);
820 Read(&aSoundDescriptionV1
->desc
.SampleRate
);
822 if ((aSoundDescriptionV1
->desc
.Version
== 1) && (aSoundDescriptionV1
->basefields
.DataFormat
!= AUDIO_IMA4
)) {
823 Read(&(aSoundDescriptionV1
->samplesPerPacket
));
824 Read(&(aSoundDescriptionV1
->bytesPerPacket
));
825 Read(&(aSoundDescriptionV1
->bytesPerFrame
));
826 Read(&(aSoundDescriptionV1
->bytesPerSample
));
830 if (aSoundDescriptionV1
->basefields
.DataFormat
== AUDIO_IMA4
) {
831 aSoundDescriptionV1
->samplesPerPacket
= 64;
832 aSoundDescriptionV1
->bytesPerFrame
= aSoundDescriptionV1
->desc
.NoOfChannels
* 34;
834 aSoundDescriptionV1
->bytesPerSample
= aSoundDescriptionV1
->desc
.SampleSize
/ 8;
835 aSoundDescriptionV1
->bytesPerPacket
= 64 * aSoundDescriptionV1
->bytesPerFrame
;
837 aSoundDescriptionV1
->bytesPerSample
= aSoundDescriptionV1
->desc
.SampleSize
/ 8;
838 aSoundDescriptionV1
->bytesPerFrame
= aSoundDescriptionV1
->desc
.NoOfChannels
* aSoundDescriptionV1
->bytesPerSample
;
839 aSoundDescriptionV1
->bytesPerPacket
= aSoundDescriptionV1
->desc
.PacketSize
;
840 aSoundDescriptionV1
->samplesPerPacket
= aSoundDescriptionV1
->desc
.PacketSize
/ aSoundDescriptionV1
->bytesPerFrame
;
844 // 0 means we dont have one
845 aSoundDescriptionV1
->theWaveFormat
.format_tag
= 0;
847 descBytesLeft
= getBytesRemaining();
849 while (descBytesLeft
> 0) {
851 // More extended atoms
852 AtomBase
*aAtomBase
= getAtom(theStream
);
854 aAtomBase
->OnProcessMetaData();
855 printf("%s\n",aAtomBase
->getAtomName());
857 if (dynamic_cast<WAVEAtom
*>(aAtomBase
)) {
859 aSoundDescriptionV1
->theWaveFormat
= dynamic_cast<WAVEAtom
*>(aAtomBase
)->getWaveFormat();
862 if (dynamic_cast<ESDSAtom
*>(aAtomBase
)) {
864 aSoundDescriptionV1
->VOLSize
= aAtomBase
->getDataSize();
865 aSoundDescriptionV1
->theVOL
= (uint8
*)(malloc(aSoundDescriptionV1
->VOLSize
));
866 memcpy(aSoundDescriptionV1
->theVOL
,dynamic_cast<ESDSAtom
*>(aAtomBase
)->getVOL(),aSoundDescriptionV1
->VOLSize
);
869 if ((aAtomBase
->getAtomSize() > 0) && (descBytesLeft
>= aAtomBase
->getAtomSize())) {
870 descBytesLeft
= descBytesLeft
- aAtomBase
->getAtomSize();
872 DEBUGGER("Invalid Atom found when reading Sound Description\n");
879 theAudioDescArray
[0] = aSoundDescriptionV1
;
881 PRINT(("Size:Format=%ld:%ld %Ld\n",aSoundDescriptionV1
->basefields
.Size
,aSoundDescriptionV1
->basefields
.DataFormat
,descBytesLeft
));
884 void STSDAtom::ReadVideoDescription()
886 uint64 descBytesLeft
;
888 // read in Video Sample Data
889 VideoDescriptionV0
*aVideoDescription
;
891 aVideoDescription
= new VideoDescriptionV0
;
893 Read(&aVideoDescription
->basefields
.Size
);
894 Read(&aVideoDescription
->basefields
.DataFormat
);
895 Read(aVideoDescription
->basefields
.Reserved
,6);
896 Read(&aVideoDescription
->basefields
.DataReference
);
898 Read(&aVideoDescription
->desc
.Version
);
899 Read(&aVideoDescription
->desc
.Revision
);
900 Read(&aVideoDescription
->desc
.Vendor
);
901 Read(&aVideoDescription
->desc
.TemporaralQuality
);
902 Read(&aVideoDescription
->desc
.SpacialQuality
);
903 Read(&aVideoDescription
->desc
.Width
);
904 Read(&aVideoDescription
->desc
.Height
);
905 Read(&aVideoDescription
->desc
.HorizontalResolution
);
906 Read(&aVideoDescription
->desc
.VerticalResolution
);
907 Read(&aVideoDescription
->desc
.DataSize
);
908 // FrameCount is actually No of Frames per Sample which is usually 1
909 Read(&aVideoDescription
->desc
.FrameCount
);
910 Read(aVideoDescription
->desc
.CompressorName
,32);
911 Read(&aVideoDescription
->desc
.Depth
);
912 Read(&aVideoDescription
->desc
.ColourTableID
);
914 aVideoDescription
->VOLSize
= 0;
915 aVideoDescription
->theVOL
= NULL
;
917 theVideoDescArray
[0] = aVideoDescription
;
919 descBytesLeft
= getBytesRemaining();
922 // If not then seek back to where we are as it may be a complete new video description
924 if (descBytesLeft
> 0) {
926 off_t pos
= theStream
->Position();
927 // More extended atoms
928 AtomBase
*aAtomBase
= getAtom(theStream
);
930 aAtomBase
->OnProcessMetaData();
931 printf("%s\n",aAtomBase
->getAtomName());
933 if (dynamic_cast<ESDSAtom
*>(aAtomBase
)) {
935 aVideoDescription
->VOLSize
= aAtomBase
->getDataSize();
936 aVideoDescription
->theVOL
= (uint8
*)(malloc(aVideoDescription
->VOLSize
));
937 memcpy(aVideoDescription
->theVOL
,dynamic_cast<ESDSAtom
*>(aAtomBase
)->getVOL(),aVideoDescription
->VOLSize
);
940 theStream
->Seek(pos
,SEEK_SET
);
946 PRINT(("Size:Format=%ld:%ld %Ld\n",aVideoDescription
->basefields
.Size
,aVideoDescription
->basefields
.DataFormat
,getBytesRemaining()));
949 void STSDAtom::OnProcessMetaData()
951 ReadArrayHeader(&theHeader
);
953 for (uint32 i
=0;i
<theHeader
.NoEntries
;i
++) {
955 switch (getMediaComponentSubType()) {
957 ReadSoundDescription();
960 ReadVideoDescription();
964 SampleDescBase aSampleDescBase
;
965 Read(&aSampleDescBase
.Size
);
966 Read(&aSampleDescBase
.DataFormat
);
967 Read(aSampleDescBase
.Reserved
,6);
968 Read(&aSampleDescBase
.DataReference
);
970 printf("%c%c%c%c\n",char(aSampleDescBase
.DataFormat
>>24),char(aSampleDescBase
.DataFormat
>>16),char(aSampleDescBase
.DataFormat
>>8),char(aSampleDescBase
.DataFormat
));
972 theStream
->Seek(aSampleDescBase
.Size
- SampleDescBaseSize
, SEEK_CUR
);
978 VideoDescriptionV0
STSDAtom::getAsVideo()
980 // Assert IsVideo - how will we handle multiples
981 return *theVideoDescArray
[0];
984 SoundDescriptionV1
STSDAtom::getAsAudio()
986 // Assert IsAudio - how will we handle multiples
987 return *theAudioDescArray
[0];
990 char *STSDAtom::OnGetAtomName()
992 return "Sample Description Atom";
995 WAVEAtom::WAVEAtom(BPositionIO
*pStream
, off_t pstreamOffset
, uint32 patomType
, uint64 patomSize
) : AtomBase(pStream
, pstreamOffset
, patomType
, patomSize
)
999 WAVEAtom::~WAVEAtom()
1003 void WAVEAtom::OnProcessMetaData()
1005 // This should be in LITTLE ENDIAN DATA
1006 theStream
->Read(&theWaveFormat
.format_tag
,sizeof(uint16
));
1007 theStream
->Read(&theWaveFormat
.channels
,sizeof(uint16
));
1008 theStream
->Read(&theWaveFormat
.frames_per_sec
,sizeof(uint32
));
1009 theStream
->Read(&theWaveFormat
.avg_bytes_per_sec
,sizeof(uint32
));
1010 theStream
->Read(&theWaveFormat
.block_align
,sizeof(uint16
));
1011 theStream
->Read(&theWaveFormat
.bits_per_sample
,sizeof(uint16
));
1012 theStream
->Read(&theWaveFormat
.extra_size
,sizeof(uint16
));
1014 theWaveFormat
.format_tag
= B_LENDIAN_TO_HOST_INT16(theWaveFormat
.format_tag
);
1015 theWaveFormat
.channels
= B_LENDIAN_TO_HOST_INT16(theWaveFormat
.channels
);
1016 theWaveFormat
.frames_per_sec
= B_LENDIAN_TO_HOST_INT32(theWaveFormat
.frames_per_sec
);
1017 theWaveFormat
.avg_bytes_per_sec
= B_LENDIAN_TO_HOST_INT32(theWaveFormat
.avg_bytes_per_sec
);
1018 theWaveFormat
.block_align
= B_LENDIAN_TO_HOST_INT16(theWaveFormat
.block_align
);
1019 theWaveFormat
.bits_per_sample
= B_LENDIAN_TO_HOST_INT16(theWaveFormat
.bits_per_sample
);
1020 theWaveFormat
.extra_size
= B_LENDIAN_TO_HOST_INT16(theWaveFormat
.extra_size
);
1023 char *WAVEAtom::OnGetAtomName()
1025 return "WAVE structure Atom";
1028 TMCDAtom::TMCDAtom(BPositionIO
*pStream
, off_t pstreamOffset
, uint32 patomType
, uint64 patomSize
) : AtomBase(pStream
, pstreamOffset
, patomType
, patomSize
)
1032 TMCDAtom::~TMCDAtom()
1036 void TMCDAtom::OnProcessMetaData()
1040 char *TMCDAtom::OnGetAtomName()
1042 return "TimeCode Atom";
1045 WIDEAtom::WIDEAtom(BPositionIO
*pStream
, off_t pstreamOffset
, uint32 patomType
, uint64 patomSize
) : AtomBase(pStream
, pstreamOffset
, patomType
, patomSize
)
1049 WIDEAtom::~WIDEAtom()
1053 void WIDEAtom::OnProcessMetaData()
1057 char *WIDEAtom::OnGetAtomName()
1062 FREEAtom::FREEAtom(BPositionIO
*pStream
, off_t pstreamOffset
, uint32 patomType
, uint64 patomSize
) : AtomBase(pStream
, pstreamOffset
, patomType
, patomSize
)
1066 FREEAtom::~FREEAtom()
1070 void FREEAtom::OnProcessMetaData()
1074 char *FREEAtom::OnGetAtomName()
1079 PNOTAtom::PNOTAtom(BPositionIO
*pStream
, off_t pstreamOffset
, uint32 patomType
, uint64 patomSize
) : AtomBase(pStream
, pstreamOffset
, patomType
, patomSize
)
1083 PNOTAtom::~PNOTAtom()
1087 void PNOTAtom::OnProcessMetaData()
1091 char *PNOTAtom::OnGetAtomName()
1093 return "Preview Atom";
1096 SKIPAtom::SKIPAtom(BPositionIO
*pStream
, off_t pstreamOffset
, uint32 patomType
, uint64 patomSize
) : AtomBase(pStream
, pstreamOffset
, patomType
, patomSize
)
1100 SKIPAtom::~SKIPAtom()
1104 void SKIPAtom::OnProcessMetaData()
1108 char *SKIPAtom::OnGetAtomName()
1113 MDATAtom::MDATAtom(BPositionIO
*pStream
, off_t pstreamOffset
, uint32 patomType
, uint64 patomSize
) : AtomBase(pStream
, pstreamOffset
, patomType
, patomSize
)
1117 MDATAtom::~MDATAtom()
1121 void MDATAtom::OnProcessMetaData()
1125 char *MDATAtom::OnGetAtomName()
1127 return "Media Data Atom";
1130 off_t
MDATAtom::getEOF()
1132 return getStreamOffset() + getAtomSize();
1135 MINFAtom::MINFAtom(BPositionIO
*pStream
, off_t pstreamOffset
, uint32 patomType
, uint64 patomSize
) : AtomContainer(pStream
, pstreamOffset
, patomType
, patomSize
)
1139 MINFAtom::~MINFAtom()
1143 void MINFAtom::OnProcessMetaData()
1147 char *MINFAtom::OnGetAtomName()
1149 return "Quicktime Media Information Atom";
1152 uint32
MINFAtom::getMediaComponentSubType()
1154 return dynamic_cast<MDIAAtom
*>(getParent())->getMediaComponentSubType();
1157 STBLAtom::STBLAtom(BPositionIO
*pStream
, off_t pstreamOffset
, uint32 patomType
, uint64 patomSize
) : AtomContainer(pStream
, pstreamOffset
, patomType
, patomSize
)
1161 STBLAtom::~STBLAtom()
1165 void STBLAtom::OnProcessMetaData()
1169 char *STBLAtom::OnGetAtomName()
1171 return "Quicktime Sample Table Atom";
1174 uint32
STBLAtom::getMediaComponentSubType()
1176 return dynamic_cast<MINFAtom
*>(getParent())->getMediaComponentSubType();
1179 DINFAtom::DINFAtom(BPositionIO
*pStream
, off_t pstreamOffset
, uint32 patomType
, uint64 patomSize
) : AtomContainer(pStream
, pstreamOffset
, patomType
, patomSize
)
1183 DINFAtom::~DINFAtom()
1187 void DINFAtom::OnProcessMetaData()
1191 char *DINFAtom::OnGetAtomName()
1193 return "Quicktime Data Information Atom";
1196 TKHDAtom::TKHDAtom(BPositionIO
*pStream
, off_t pstreamOffset
, uint32 patomType
, uint64 patomSize
) : AtomBase(pStream
, pstreamOffset
, patomType
, patomSize
)
1200 TKHDAtom::~TKHDAtom()
1204 void TKHDAtom::OnProcessMetaData()
1209 // Read into V0 header and convert to V1 Header
1212 Read(&aHeaderV0
.Flags1
);
1213 Read(&aHeaderV0
.Flags2
);
1214 Read(&aHeaderV0
.Flags3
);
1215 Read(&aHeaderV0
.CreationTime
);
1216 Read(&aHeaderV0
.ModificationTime
);
1217 Read(&aHeaderV0
.TrackID
);
1218 Read(&aHeaderV0
.Reserved1
);
1219 Read(&aHeaderV0
.Duration
);
1220 Read(&aHeaderV0
.Reserved2
);
1221 Read(&aHeaderV0
.Layer
);
1222 Read(&aHeaderV0
.AlternateGroup
);
1223 Read(&aHeaderV0
.Volume
);
1224 Read(&aHeaderV0
.Reserved3
);
1225 Read(aHeaderV0
.MatrixStructure
,36);
1226 Read(&aHeaderV0
.TrackWidth
);
1227 Read(&aHeaderV0
.TrackHeight
);
1229 theHeader
.Flags1
= aHeaderV0
.Flags1
;
1230 theHeader
.Flags2
= aHeaderV0
.Flags2
;
1231 theHeader
.Flags3
= aHeaderV0
.Flags3
;
1232 theHeader
.Reserved1
= aHeaderV0
.Reserved1
;
1233 theHeader
.Reserved2
= aHeaderV0
.Reserved2
;
1234 theHeader
.Reserved3
= aHeaderV0
.Reserved3
;
1236 for (uint32 i
=0;i
<36;i
++) {
1237 theHeader
.MatrixStructure
[i
] = aHeaderV0
.MatrixStructure
[i
];
1240 // upconvert to V1 header
1241 theHeader
.CreationTime
= uint64(aHeaderV0
.CreationTime
);
1242 theHeader
.ModificationTime
= uint64(aHeaderV0
.ModificationTime
);
1243 theHeader
.TrackID
= aHeaderV0
.TrackID
;
1244 theHeader
.Duration
= aHeaderV0
.Duration
;
1245 theHeader
.Layer
= aHeaderV0
.Layer
;
1246 theHeader
.AlternateGroup
= aHeaderV0
.AlternateGroup
;
1247 theHeader
.Volume
= aHeaderV0
.Volume
;
1248 theHeader
.TrackWidth
= aHeaderV0
.TrackWidth
;
1249 theHeader
.TrackHeight
= aHeaderV0
.TrackHeight
;
1252 // Read direct into V1 Header
1253 Read(&theHeader
.Flags1
);
1254 Read(&theHeader
.Flags2
);
1255 Read(&theHeader
.Flags3
);
1256 Read(&theHeader
.CreationTime
);
1257 Read(&theHeader
.ModificationTime
);
1258 Read(&theHeader
.TrackID
);
1259 Read(&theHeader
.Reserved1
);
1260 Read(&theHeader
.Duration
);
1261 Read(&theHeader
.Reserved2
);
1262 Read(&theHeader
.Layer
);
1263 Read(&theHeader
.AlternateGroup
);
1264 Read(&theHeader
.Volume
);
1265 Read(&theHeader
.Reserved3
);
1266 Read(theHeader
.MatrixStructure
,36);
1267 Read(&theHeader
.TrackWidth
);
1268 Read(&theHeader
.TrackHeight
);
1273 char *TKHDAtom::OnGetAtomName()
1275 return "Quicktime Track Header";
1278 MDIAAtom::MDIAAtom(BPositionIO
*pStream
, off_t pstreamOffset
, uint32 patomType
, uint64 patomSize
) : AtomContainer(pStream
, pstreamOffset
, patomType
, patomSize
)
1282 MDIAAtom::~MDIAAtom()
1286 void MDIAAtom::OnProcessMetaData()
1290 char *MDIAAtom::OnGetAtomName()
1292 return "Quicktime Media Atom";
1295 uint32
MDIAAtom::getMediaComponentSubType()
1297 // get child atom hdlr
1298 HDLRAtom
*aHDLRAtom
;
1299 aHDLRAtom
= dynamic_cast<HDLRAtom
*>(GetChildAtom(uint32('hdlr')));
1302 return aHDLRAtom
->getMediaComponentSubType();
1308 MDHDAtom::MDHDAtom(BPositionIO
*pStream
, off_t pstreamOffset
, uint32 patomType
, uint64 patomSize
) : AtomBase(pStream
, pstreamOffset
, patomType
, patomSize
)
1312 MDHDAtom::~MDHDAtom()
1316 void MDHDAtom::OnProcessMetaData()
1318 Read(&theHeader
.Version
);
1319 Read(&theHeader
.Flags1
);
1320 Read(&theHeader
.Flags2
);
1321 Read(&theHeader
.Flags3
);
1322 Read(&theHeader
.CreationTime
);
1323 Read(&theHeader
.ModificationTime
);
1324 Read(&theHeader
.TimeScale
);
1325 Read(&theHeader
.Duration
);
1326 Read(&theHeader
.Language
);
1327 Read(&theHeader
.Quality
);
1330 char *MDHDAtom::OnGetAtomName()
1332 return "Quicktime Media Header";
1335 bigtime_t
MDHDAtom::getDuration()
1337 return bigtime_t((uint64(theHeader
.Duration
) * 1000000L) / theHeader
.TimeScale
);
1340 uint32
MDHDAtom::getTimeScale()
1342 return theHeader
.TimeScale
;
1345 HDLRAtom::HDLRAtom(BPositionIO
*pStream
, off_t pstreamOffset
, uint32 patomType
, uint64 patomSize
) : AtomBase(pStream
, pstreamOffset
, patomType
, patomSize
)
1349 HDLRAtom::~HDLRAtom()
1353 void HDLRAtom::OnProcessMetaData()
1355 Read(&theHeader
.Version
);
1356 Read(&theHeader
.Flags1
);
1357 Read(&theHeader
.Flags2
);
1358 Read(&theHeader
.Flags3
);
1359 Read(&theHeader
.ComponentType
);
1360 Read(&theHeader
.ComponentSubType
);
1361 Read(&theHeader
.ComponentManufacturer
);
1362 Read(&theHeader
.ComponentFlags
);
1363 Read(&theHeader
.ComponentFlagsMask
);
1365 // Read Array of Strings?
1368 char *HDLRAtom::OnGetAtomName()
1370 return "Quicktime Handler Reference Atom ";
1373 bool HDLRAtom::IsVideoHandler()
1375 return (theHeader
.ComponentSubType
== 'vide');
1378 bool HDLRAtom::IsAudioHandler()
1380 return (theHeader
.ComponentSubType
== 'soun');
1383 uint32
HDLRAtom::getMediaComponentSubType()
1385 return theHeader
.ComponentSubType
;
1388 VMHDAtom::VMHDAtom(BPositionIO
*pStream
, off_t pstreamOffset
, uint32 patomType
, uint64 patomSize
) : AtomBase(pStream
, pstreamOffset
, patomType
, patomSize
)
1392 VMHDAtom::~VMHDAtom()
1396 void VMHDAtom::OnProcessMetaData()
1399 Read(&aHeader
.Version
);
1400 Read(&aHeader
.Flags1
);
1401 Read(&aHeader
.Flags2
);
1402 Read(&aHeader
.Flags3
);
1403 Read(&aHeader
.GraphicsMode
);
1404 Read(&aHeader
.OpColourRed
);
1405 Read(&aHeader
.OpColourGreen
);
1406 Read(&aHeader
.OpColourBlue
);
1409 char *VMHDAtom::OnGetAtomName()
1411 return "Quicktime Video Media Header";
1414 SMHDAtom::SMHDAtom(BPositionIO
*pStream
, off_t pstreamOffset
, uint32 patomType
, uint64 patomSize
) : AtomBase(pStream
, pstreamOffset
, patomType
, patomSize
)
1418 SMHDAtom::~SMHDAtom()
1422 void SMHDAtom::OnProcessMetaData()
1425 Read(&aHeader
.Version
);
1426 Read(&aHeader
.Flags1
);
1427 Read(&aHeader
.Flags2
);
1428 Read(&aHeader
.Flags3
);
1429 Read(&aHeader
.Balance
);
1430 Read(&aHeader
.Reserved
);
1433 char *SMHDAtom::OnGetAtomName()
1435 return "Quicktime Sound Media Header";
1438 FTYPAtom::FTYPAtom(BPositionIO
*pStream
, off_t pstreamOffset
, uint32 patomType
, uint64 patomSize
) : AtomBase(pStream
, pstreamOffset
, patomType
, patomSize
)
1442 FTYPAtom::~FTYPAtom()
1446 void FTYPAtom::OnProcessMetaData()
1448 // ftyp is really an mp4 thing, but some mov encoders are adding it anyway.
1449 // but a mov file with an ftyp should define a brand of qt (I think)
1452 Read(&minor_version
);
1454 total_brands
= getBytesRemaining() / sizeof(uint32
);
1456 if (total_brands
> 32) {
1457 total_brands
= 32; // restrict to 32
1460 for (uint32 i
=0;i
<total_brands
;i
++) {
1461 Read(&compatable_brands
[i
]);
1465 char *FTYPAtom::OnGetAtomName()
1467 return "Quicktime File Type";
1470 bool FTYPAtom::HasBrand(uint32 brand
)
1472 // return true if the specified brand is in the list
1474 if (major_brand
== brand
) {
1478 for (uint32 i
=0;i
<total_brands
;i
++) {
1479 if (compatable_brands
[i
] == brand
) {