vfs: check userland buffers before reading them.
[haiku.git] / src / add-ons / media / plugins / mov_reader / libMOV / MOVParser.cpp
blob119ae252bf2992eeec8fc4a0fa8817ad878b2ea0
1 /*
2 * Copyright (c) 2005, David McPaul
3 * All rights reserved.
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.
25 #include <stdio.h>
27 #include <DataIO.h>
28 #include <SupportKit.h>
29 #include <MediaFormats.h>
31 #ifdef __HAIKU__
32 #include <libs/zlib/zlib.h>
33 #else
34 #include <zlib.h>
35 #endif
37 #include "MOVParser.h"
39 //static
40 AtomBase *getAtom(BPositionIO *pStream)
42 uint32 aAtomType;
43 uint32 aAtomSize;
44 uint64 aRealAtomSize;
45 off_t aStreamOffset;
47 aStreamOffset = pStream->Position();
49 // Get Size uint32
50 pStream->Read(&aAtomSize,4);
51 aAtomSize = B_BENDIAN_TO_HOST_INT32(aAtomSize);
52 // Get Type uint32
53 pStream->Read(&aAtomType,4);
54 aAtomType = B_BENDIAN_TO_HOST_INT32(aAtomType);
55 // Check for extended size
56 if (aAtomSize == 1) {
57 // Handle extended size
58 pStream->Read(&aRealAtomSize,4);
59 aRealAtomSize = B_BENDIAN_TO_HOST_INT64(aRealAtomSize);
60 } else {
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)
194 theMVHDAtom = NULL;
197 MOOVAtom::~MOOVAtom()
199 theMVHDAtom = NULL;
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;
227 return theStream;
230 void CMOVAtom::OnProcessMetaData()
232 BMallocIO *theUncompressedData;
233 uint8 *outBuffer;
234 CMVDAtom *aCMVDAtom = NULL;
235 uint32 compressionID = 0;
236 uint64 descBytesLeft;
237 uint32 Size;
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();
250 } else {
251 printf("Invalid Atom found when reading Compressed Headers\n");
252 descBytesLeft = 0;
255 if (dynamic_cast<DCOMAtom *>(aAtomBase)) {
256 // DCOM atom
257 compressionID = dynamic_cast<DCOMAtom *>(aAtomBase)->getCompressionID();
258 delete aAtomBase;
259 } else {
260 if (dynamic_cast<CMVDAtom *>(aAtomBase)) {
261 // CMVD atom
262 aCMVDAtom = dynamic_cast<CMVDAtom *>(aAtomBase);
263 descBytesLeft = 0;
268 // Decompress data
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 ");
279 switch (result) {
280 case Z_MEM_ERROR:
281 DEBUGGER("Lack of Memory Error\n");
282 break;
283 case Z_BUF_ERROR:
284 DEBUGGER("Lack of Output buffer space Error\n");
285 break;
286 case Z_DATA_ERROR:
287 DEBUGGER("Input Data is corrupt or not a compressed set Error\n");
288 break;
292 // Copy uncompressed data into BMAllocIO
293 theUncompressedData = new BMallocIO();
294 theUncompressedData->SetSize(Size);
295 theUncompressedData->WriteAt(0L,outBuffer,Size);
297 free(outBuffer);
298 delete aCMVDAtom;
300 // reset position on BMAllocIO
301 theUncompressedData->Seek(SEEK_SET,0L);
302 // Assign to Stream
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)
344 Buffer = NULL;
345 UncompressedSize = 0;
346 BufferSize = 0;
349 CMVDAtom::~CMVDAtom()
351 if (Buffer) {
352 free(Buffer);
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()
404 AtomBase *aAtomBase;
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");
412 return theMVHDAtom;
415 STTSAtom::STTSAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize) : AtomBase(pStream, pstreamOffset, patomType, patomSize)
417 theHeader.NoEntries = 0;
418 SUMDurations = 0;
419 SUMCounts = 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?
456 uint64 Duration = 0;
458 for (uint32 i=0;i<theHeader.NoEntries;i++) {
459 Duration += (theTimeToSampleArray[i]->Duration * theTimeToSampleArray[i]->Count);
460 if (Duration > pTime) {
461 return i;
465 return 0;
468 uint32 STTSAtom::getSampleForFrame(uint32 pFrame)
470 // Hmm Sample is Frame really, this Atom is more usefull for time->sample calcs
471 return pFrame;
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);
502 if (i > 0) {
503 TotalPrevSamples = TotalPrevSamples + (aSampleToChunk->FirstChunk - theSampleToChunkArray[i-1]->FirstChunk) * theSampleToChunkArray[i-1]->SamplesPerChunk;
504 aSampleToChunk->TotalPrevSamples = TotalPrevSamples;
505 } else {
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)
531 uint32 Diff;
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)
546 uint32 ChunkID = 0;
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;
558 return ChunkID;
562 *pOffsetInChunk = 0;
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) {
603 return true;
606 if (pSampleNo > theSyncSampleArray[i]->SyncSampleNo) {
607 return false;
611 return false;
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()
686 uint32 Offset;
688 Read(&Offset);
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;
723 #if DEBUG
724 char msg[100]; sprintf(msg, "Bad Chunk ID %ld / %ld\n", pChunkID, theHeader.NoEntries);
725 DEBUGGER(msg);
726 #endif
728 TRESPASS();
729 return 0LL;
732 ESDSAtom::ESDSAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize) : AtomBase(pStream, pstreamOffset, patomType, patomSize)
734 theVOL = NULL;
737 ESDSAtom::~ESDSAtom()
739 if (theVOL) {
740 free(theVOL);
744 void ESDSAtom::OnProcessMetaData()
746 theVOL = (uint8 *)(malloc(getBytesRemaining()));
747 Read(theVOL,getBytesRemaining());
750 uint8 *ESDSAtom::getVOL()
752 return theVOL;
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));
828 } else {
829 // Calculate?
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;
836 } else {
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)) {
858 // WAVE atom
859 aSoundDescriptionV1->theWaveFormat = dynamic_cast<WAVEAtom *>(aAtomBase)->getWaveFormat();
862 if (dynamic_cast<ESDSAtom *>(aAtomBase)) {
863 // ESDS atom good
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();
871 } else {
872 DEBUGGER("Invalid Atom found when reading Sound Description\n");
873 descBytesLeft = 0;
876 delete aAtomBase;
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();
921 // May be a VOL
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)) {
934 // ESDS atom good
935 aVideoDescription->VOLSize = aAtomBase->getDataSize();
936 aVideoDescription->theVOL = (uint8 *)(malloc(aVideoDescription->VOLSize));
937 memcpy(aVideoDescription->theVOL,dynamic_cast<ESDSAtom *>(aAtomBase)->getVOL(),aVideoDescription->VOLSize);
938 } else {
939 // Seek Back
940 theStream->Seek(pos,SEEK_SET);
943 delete aAtomBase;
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()) {
956 case 'soun':
957 ReadSoundDescription();
958 break;
959 case 'vide':
960 ReadVideoDescription();
961 break;
962 default:
963 // Skip
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);
973 break;
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()
1059 return "WIDE Atom";
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()
1076 return "Free Atom";
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()
1110 return "Skip Atom";
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()
1206 Read(&Version);
1208 if (Version == 0) {
1209 // Read into V0 header and convert to V1 Header
1210 tkhdV0 aHeaderV0;
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;
1251 } else {
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')));
1301 if (aHDLRAtom) {
1302 return aHDLRAtom->getMediaComponentSubType();
1305 return 0;
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()
1398 vmhd aHeader;
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()
1424 smhd aHeader;
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)
1451 Read(&major_brand);
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) {
1475 return true;
1478 for (uint32 i=0;i<total_brands;i++) {
1479 if (compatable_brands[i] == brand) {
1480 return true;
1484 return false;