1/*
2 * Copyright (c) 2005, David McPaul
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without modification,
6 * are permitted provided that the following conditions are met:
7 *
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.
13 *
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.
24 */
25#include <stdio.h>
26
27#include <DataIO.h>
28#include <SupportKit.h>
29#include <MediaFormats.h>
30
31#ifdef __HAIKU__
32#include <libs/zlib/zlib.h>
33#else
34#include <zlib.h>
35#endif
36
37#include "MOVParser.h"
38
39//static
40AtomBase *getAtom(BPositionIO *pStream)
41{
42	uint32 aAtomType;
43	uint32 aAtomSize;
44	uint64 aRealAtomSize;
45	off_t aStreamOffset;
46
47	aStreamOffset = pStream->Position();
48
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;
62	}
63
64	if (aAtomType == uint32('moov')) {
65		return new MOOVAtom(pStream, aStreamOffset, aAtomType, aRealAtomSize);
66	}
67
68	if (aAtomType == uint32('mvhd')) {
69		return new MVHDAtom(pStream, aStreamOffset, aAtomType, aRealAtomSize);
70	}
71
72	if (aAtomType == uint32('trak')) {
73		return new TRAKAtom(pStream, aStreamOffset, aAtomType, aRealAtomSize);
74	}
75
76	if (aAtomType == uint32('tkhd')) {
77		return new TKHDAtom(pStream, aStreamOffset, aAtomType, aRealAtomSize);
78	}
79
80	if (aAtomType == uint32('free')) {
81		return new FREEAtom(pStream, aStreamOffset, aAtomType, aRealAtomSize);
82	}
83
84	if (aAtomType == uint32('skip')) {
85		return new SKIPAtom(pStream, aStreamOffset, aAtomType, aRealAtomSize);
86	}
87
88	if (aAtomType == uint32('wide')) {
89		return new WIDEAtom(pStream, aStreamOffset, aAtomType, aRealAtomSize);
90	}
91
92	if (aAtomType == uint32('mdat')) {
93		return new MDATAtom(pStream, aStreamOffset, aAtomType, aRealAtomSize);
94	}
95
96	if (aAtomType == uint32('mdia')) {
97		return new MDIAAtom(pStream, aStreamOffset, aAtomType, aRealAtomSize);
98	}
99
100	if (aAtomType == uint32('mdhd')) {
101		return new MDHDAtom(pStream, aStreamOffset, aAtomType, aRealAtomSize);
102	}
103
104	if (aAtomType == uint32('hdlr')) {
105		return new HDLRAtom(pStream, aStreamOffset, aAtomType, aRealAtomSize);
106	}
107
108	if (aAtomType == uint32('minf')) {
109		return new MINFAtom(pStream, aStreamOffset, aAtomType, aRealAtomSize);
110	}
111
112	if (aAtomType == uint32('vmhd')) {
113		return new VMHDAtom(pStream, aStreamOffset, aAtomType, aRealAtomSize);
114	}
115
116	if (aAtomType == uint32('smhd')) {
117		return new SMHDAtom(pStream, aStreamOffset, aAtomType, aRealAtomSize);
118	}
119
120	if (aAtomType == uint32('dinf')) {
121		return new DINFAtom(pStream, aStreamOffset, aAtomType, aRealAtomSize);
122	}
123
124	if (aAtomType == uint32('stbl')) {
125		return new STBLAtom(pStream, aStreamOffset, aAtomType, aRealAtomSize);
126	}
127
128	if (aAtomType == uint32('stsd')) {
129		return new STSDAtom(pStream, aStreamOffset, aAtomType, aRealAtomSize);
130	}
131
132	if (aAtomType == uint32('tmcd')) {
133		return new TMCDAtom(pStream, aStreamOffset, aAtomType, aRealAtomSize);
134	}
135
136	if (aAtomType == uint32('wave')) {
137		return new WAVEAtom(pStream, aStreamOffset, aAtomType, aRealAtomSize);
138	}
139
140	if (aAtomType == uint32('stts')) {
141		return new STTSAtom(pStream, aStreamOffset, aAtomType, aRealAtomSize);
142	}
143
144	if (aAtomType == uint32('pnot')) {
145		return new PNOTAtom(pStream, aStreamOffset, aAtomType, aRealAtomSize);
146	}
147
148	if (aAtomType == uint32('stsc')) {
149		return new STSCAtom(pStream, aStreamOffset, aAtomType, aRealAtomSize);
150	}
151
152	if (aAtomType == uint32('stco')) {
153		return new STCOAtom(pStream, aStreamOffset, aAtomType, aRealAtomSize);
154	}
155
156	if (aAtomType == uint32('stss')) {
157		return new STSSAtom(pStream, aStreamOffset, aAtomType, aRealAtomSize);
158	}
159
160	if (aAtomType == uint32('stsz')) {
161		return new STSZAtom(pStream, aStreamOffset, aAtomType, aRealAtomSize);
162	}
163
164	if (aAtomType == uint32('cmov')) {
165		return new CMOVAtom(pStream, aStreamOffset, aAtomType, aRealAtomSize);
166	}
167
168	if (aAtomType == uint32('dcom')) {
169		return new DCOMAtom(pStream, aStreamOffset, aAtomType, aRealAtomSize);
170	}
171
172	if (aAtomType == uint32('cmvd')) {
173		return new CMVDAtom(pStream, aStreamOffset, aAtomType, aRealAtomSize);
174	}
175
176	if (aAtomType == uint32('esds')) {
177		return new ESDSAtom(pStream, aStreamOffset, aAtomType, aRealAtomSize);
178	}
179
180	if (aAtomType == uint32('avcC')) {
181		return new ESDSAtom(pStream, aStreamOffset, aAtomType, aRealAtomSize);
182	}
183
184	if (aAtomType == uint32('ftyp')) {
185		return new FTYPAtom(pStream, aStreamOffset, aAtomType, aRealAtomSize);
186	}
187
188	return new AtomBase(pStream, aStreamOffset, aAtomType, aRealAtomSize);
189
190}
191
192MOOVAtom::MOOVAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize) : AtomContainer(pStream, pstreamOffset, patomType, patomSize)
193{
194	theMVHDAtom = NULL;
195}
196
197MOOVAtom::~MOOVAtom()
198{
199	theMVHDAtom = NULL;
200}
201
202void MOOVAtom::OnProcessMetaData()
203{
204}
205
206char *MOOVAtom::OnGetAtomName()
207{
208	return "Quicktime Movie";
209}
210
211CMOVAtom::CMOVAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize) : AtomContainer(pStream, pstreamOffset, patomType, patomSize)
212{
213	theUncompressedStream = NULL;
214}
215
216CMOVAtom::~CMOVAtom()
217{
218}
219
220BPositionIO *CMOVAtom::OnGetStream()
221{
222	// Use the decompressed stream instead of file stream
223	if (theUncompressedStream) {
224		return theUncompressedStream;
225	}
226
227	return theStream;
228}
229
230void CMOVAtom::OnProcessMetaData()
231{
232	BMallocIO *theUncompressedData;
233	uint8 *outBuffer;
234	CMVDAtom *aCMVDAtom = NULL;
235	uint32	compressionID = 0;
236	uint64	descBytesLeft;
237	uint32	Size;
238
239	descBytesLeft = getAtomSize();
240
241	// Check for Compression Type
242	while (descBytesLeft > 0) {
243		AtomBase *aAtomBase = getAtom(theStream);
244
245		aAtomBase->OnProcessMetaData();
246		printf("%s [%Ld]\n",aAtomBase->getAtomName(),aAtomBase->getAtomSize());
247
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;
253		}
254
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;
264			}
265		}
266	}
267
268	// Decompress data
269	if (compressionID == 'zlib') {
270		Size = aCMVDAtom->getUncompressedSize();
271
272		outBuffer = (uint8 *)(malloc(Size));
273
274		printf("Decompressing %ld bytes to %ld bytes\n",aCMVDAtom->getBufferSize(),Size);
275		int result = uncompress(outBuffer, &Size, aCMVDAtom->getCompressedData(), aCMVDAtom->getBufferSize());
276
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;
289			}
290		}
291
292		// Copy uncompressed data into BMAllocIO
293		theUncompressedData = new BMallocIO();
294		theUncompressedData->SetSize(Size);
295		theUncompressedData->WriteAt(0L,outBuffer,Size);
296
297		free(outBuffer);
298		delete aCMVDAtom;
299
300		// reset position on BMAllocIO
301		theUncompressedData->Seek(SEEK_SET,0L);
302		// Assign to Stream
303		theUncompressedStream = theUncompressedData;
304
305		// All subsequent reads should use theUncompressedStream
306	}
307
308}
309
310void CMOVAtom::OnChildProcessingComplete()
311{
312	// revert back to file stream once all children have finished
313	if (theUncompressedStream) {
314		delete theUncompressedStream;
315	}
316	theUncompressedStream = NULL;
317}
318
319char *CMOVAtom::OnGetAtomName()
320{
321	return "Compressed Quicktime Movie";
322}
323
324DCOMAtom::DCOMAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize) : AtomBase(pStream, pstreamOffset, patomType, patomSize)
325{
326}
327
328DCOMAtom::~DCOMAtom()
329{
330}
331
332void DCOMAtom::OnProcessMetaData()
333{
334	Read(&compressionID);
335}
336
337char *DCOMAtom::OnGetAtomName()
338{
339	return "Decompression Atom";
340}
341
342CMVDAtom::CMVDAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize) : AtomBase(pStream, pstreamOffset, patomType, patomSize)
343{
344	Buffer = NULL;
345	UncompressedSize = 0;
346	BufferSize = 0;
347}
348
349CMVDAtom::~CMVDAtom()
350{
351	if (Buffer) {
352		free(Buffer);
353	}
354}
355
356void CMVDAtom::OnProcessMetaData()
357{
358	Read(&UncompressedSize);
359
360	if (UncompressedSize > 0) {
361		BufferSize = getBytesRemaining();
362		Buffer = (uint8 *)(malloc(BufferSize));
363		Read(Buffer,BufferSize);
364	}
365}
366
367char *CMVDAtom::OnGetAtomName()
368{
369	return "Compressed Movie Data";
370}
371
372MVHDAtom::MVHDAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize) : AtomBase(pStream, pstreamOffset, patomType, patomSize)
373{
374}
375
376MVHDAtom::~MVHDAtom()
377{
378}
379
380void MVHDAtom::OnProcessMetaData()
381{
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);
395}
396
397char *MVHDAtom::OnGetAtomName()
398{
399	return "Quicktime Movie Header";
400}
401
402MVHDAtom *MOOVAtom::getMVHDAtom()
403{
404AtomBase *aAtomBase;
405
406	if (theMVHDAtom == NULL) {
407		aAtomBase = GetChildAtom(uint32('mvhd'));
408		theMVHDAtom = dynamic_cast<MVHDAtom *>(aAtomBase);
409	}
410
411	// Assert(theMVHDAtom != NULL,"Movie has no movie header atom");
412	return theMVHDAtom;
413}
414
415STTSAtom::STTSAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize) : AtomBase(pStream, pstreamOffset, patomType, patomSize)
416{
417	theHeader.NoEntries = 0;
418	SUMDurations = 0;
419	SUMCounts = 0;
420}
421
422STTSAtom::~STTSAtom()
423{
424	for (uint32 i=0;i<theHeader.NoEntries;i++) {
425		delete theTimeToSampleArray[i];
426		theTimeToSampleArray[i] = NULL;
427	}
428}
429
430void STTSAtom::OnProcessMetaData()
431{
432TimeToSample	*aTimeToSample;
433
434	ReadArrayHeader(&theHeader);
435
436	for (uint32 i=0;i<theHeader.NoEntries;i++) {
437		aTimeToSample = new TimeToSample;
438
439		Read(&aTimeToSample->Count);
440		Read(&aTimeToSample->Duration);
441
442		theTimeToSampleArray[i] = aTimeToSample;
443		SUMDurations += (theTimeToSampleArray[i]->Duration * theTimeToSampleArray[i]->Count);
444		SUMCounts += theTimeToSampleArray[i]->Count;
445	}
446}
447
448char *STTSAtom::OnGetAtomName()
449{
450	return "Time to Sample Atom";
451}
452
453uint32	STTSAtom::getSampleForTime(uint32 pTime)
454{
455// TODO this is too slow.  PreCalc when loading this?
456	uint64 Duration = 0;
457
458	for (uint32 i=0;i<theHeader.NoEntries;i++) {
459		Duration += (theTimeToSampleArray[i]->Duration * theTimeToSampleArray[i]->Count);
460		if (Duration > pTime) {
461			return i;
462		}
463	}
464
465	return 0;
466}
467
468uint32	STTSAtom::getSampleForFrame(uint32 pFrame)
469{
470// Hmm Sample is Frame really, this Atom is more usefull for time->sample calcs
471	return pFrame;
472}
473
474STSCAtom::STSCAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize) : AtomBase(pStream, pstreamOffset, patomType, patomSize)
475{
476	theHeader.NoEntries = 0;
477}
478
479STSCAtom::~STSCAtom()
480{
481	for (uint32 i=0;i<theHeader.NoEntries;i++) {
482		delete theSampleToChunkArray[i];
483		theSampleToChunkArray[i] = NULL;
484	}
485}
486
487void STSCAtom::OnProcessMetaData()
488{
489SampleToChunk	*aSampleToChunk;
490
491	ReadArrayHeader(&theHeader);
492
493	uint32	TotalPrevSamples = 0;
494
495	for (uint32 i=0;i<theHeader.NoEntries;i++) {
496		aSampleToChunk = new SampleToChunk;
497
498		Read(&aSampleToChunk->FirstChunk);
499		Read(&aSampleToChunk->SamplesPerChunk);
500		Read(&aSampleToChunk->SampleDescriptionID);
501
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;
507		}
508
509		theSampleToChunkArray[i] = aSampleToChunk;
510	}
511}
512
513char *STSCAtom::OnGetAtomName()
514{
515	return "Sample to Chunk Atom";
516}
517
518uint32	STSCAtom::getNoSamplesInChunk(uint32 pChunkID)
519{
520	for (uint32 i=0;i<theHeader.NoEntries;i++) {
521		if (theSampleToChunkArray[i]->FirstChunk > pChunkID) {
522			return theSampleToChunkArray[i-1]->SamplesPerChunk;
523		}
524	}
525
526	return theSampleToChunkArray[theHeader.NoEntries-1]->SamplesPerChunk;
527}
528
529uint32	STSCAtom::getFirstSampleInChunk(uint32 pChunkID)
530{
531uint32 Diff;
532
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);
537		}
538	}
539
540	Diff = pChunkID - theSampleToChunkArray[theHeader.NoEntries-1]->FirstChunk;
541	return ((Diff * theSampleToChunkArray[theHeader.NoEntries-1]->SamplesPerChunk) + theSampleToChunkArray[theHeader.NoEntries-1]->TotalPrevSamples);
542}
543
544uint32	STSCAtom::getChunkForSample(uint32 pSample, uint32 *pOffsetInChunk)
545{
546	uint32 ChunkID = 0;
547	uint32 OffsetInChunk = 0;
548
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;
554
555			OffsetInChunk = (pSample - theSampleToChunkArray[i]->TotalPrevSamples) % theSampleToChunkArray[i]->SamplesPerChunk;
556
557			*pOffsetInChunk = OffsetInChunk;
558			return ChunkID;
559		}
560	}
561
562	*pOffsetInChunk = 0;
563	return theSampleToChunkArray[theHeader.NoEntries-1]->FirstChunk;
564}
565
566STSSAtom::STSSAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize) : AtomBase(pStream, pstreamOffset, patomType, patomSize)
567{
568	theHeader.NoEntries = 0;
569}
570
571STSSAtom::~STSSAtom()
572{
573	for (uint32 i=0;i<theHeader.NoEntries;i++) {
574		delete theSyncSampleArray[i];
575		theSyncSampleArray[i] = NULL;
576	}
577}
578
579void STSSAtom::OnProcessMetaData()
580{
581SyncSample	*aSyncSample;
582
583	ReadArrayHeader(&theHeader);
584
585	for (uint32 i=0;i<theHeader.NoEntries;i++) {
586		aSyncSample = new SyncSample;
587
588		Read(&aSyncSample->SyncSampleNo);
589		theSyncSampleArray[i] = aSyncSample;
590	}
591}
592
593char *STSSAtom::OnGetAtomName()
594{
595	return "Sync Sample Atom";
596}
597
598bool	STSSAtom::IsSyncSample(uint32 pSampleNo)
599{
600
601	for (uint32 i=0;i<theHeader.NoEntries;i++) {
602		if (theSyncSampleArray[i]->SyncSampleNo == pSampleNo) {
603			return true;
604		}
605
606		if (pSampleNo > theSyncSampleArray[i]->SyncSampleNo) {
607			return false;
608		}
609	}
610
611	return false;
612}
613
614STSZAtom::STSZAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize) : AtomBase(pStream, pstreamOffset, patomType, patomSize)
615{
616	theHeader.NoEntries = 0;
617}
618
619STSZAtom::~STSZAtom()
620{
621	for (uint32 i=0;i<theHeader.NoEntries;i++) {
622		delete theSampleSizeArray[i];
623		theSampleSizeArray[i] = NULL;
624	}
625}
626
627void STSZAtom::OnProcessMetaData()
628{
629SampleSizeEntry	*aSampleSize;
630
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);
638
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;
643
644			Read(&aSampleSize->EntrySize);
645			theSampleSizeArray[i] = aSampleSize;
646		}
647	}
648}
649
650char *STSZAtom::OnGetAtomName()
651{
652	return "Sample Size Atom";
653}
654
655uint32	STSZAtom::getSizeForSample(uint32 pSampleNo)
656{
657	if (theHeader.SampleSize > 0) {
658		// All samples are the same size
659		return theHeader.SampleSize;
660	}
661
662	// Sample Array indexed by SampleNo
663	return theSampleSizeArray[pSampleNo]->EntrySize;
664}
665
666bool	STSZAtom::IsSingleSampleSize()
667{
668	return (theHeader.SampleSize > 0);
669}
670
671STCOAtom::STCOAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize) : AtomBase(pStream, pstreamOffset, patomType, patomSize)
672{
673	theHeader.NoEntries = 0;
674}
675
676STCOAtom::~STCOAtom()
677{
678	for (uint32 i=0;i<theHeader.NoEntries;i++) {
679		delete theChunkToOffsetArray[i];
680		theChunkToOffsetArray[i] = NULL;
681	}
682}
683
684uint64 STCOAtom::OnGetChunkOffset()
685{
686	uint32 Offset;
687
688	Read(&Offset);
689
690	// Upconvert to uint64
691	return uint64(Offset);
692}
693
694void STCOAtom::OnProcessMetaData()
695{
696ChunkToOffset	*aChunkToOffset;
697
698	ReadArrayHeader(&theHeader);
699
700	for (uint32 i=0;i<theHeader.NoEntries;i++) {
701		aChunkToOffset = new ChunkToOffset;
702
703		aChunkToOffset->Offset = OnGetChunkOffset();
704
705		theChunkToOffsetArray[i] = aChunkToOffset;
706	}
707
708	PRINT(("Chunk to Offset Array has %ld entries\n",theHeader.NoEntries));
709}
710
711char *STCOAtom::OnGetAtomName()
712{
713	return "Chunk to Offset Atom";
714}
715
716uint64	STCOAtom::getOffsetForChunk(uint32 pChunkID)
717{
718	// First chunk is first array entry
719	if ((pChunkID > 0) && (pChunkID <= theHeader.NoEntries)) {
720		return theChunkToOffsetArray[pChunkID - 1]->Offset;
721	}
722
723	#if DEBUG
724	  char msg[100]; sprintf(msg, "Bad Chunk ID %ld / %ld\n", pChunkID, theHeader.NoEntries);
725	  DEBUGGER(msg);
726	#endif
727
728	TRESPASS();
729	return 0LL;
730}
731
732ESDSAtom::ESDSAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize) : AtomBase(pStream, pstreamOffset, patomType, patomSize)
733{
734	theVOL = NULL;
735}
736
737ESDSAtom::~ESDSAtom()
738{
739	if (theVOL) {
740		free(theVOL);
741	}
742}
743
744void ESDSAtom::OnProcessMetaData()
745{
746	theVOL = (uint8 *)(malloc(getBytesRemaining()));
747	Read(theVOL,getBytesRemaining());
748}
749
750uint8 *ESDSAtom::getVOL()
751{
752	return theVOL;
753}
754
755char *ESDSAtom::OnGetAtomName()
756{
757	return "Extended Sample Description Atom";
758}
759
760STSDAtom::STSDAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize) : AtomBase(pStream, pstreamOffset, patomType, patomSize)
761{
762	theHeader.NoEntries = 0;
763}
764
765STSDAtom::~STSDAtom()
766{
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;
772			}
773
774			delete theAudioDescArray[i];
775			theAudioDescArray[i] = NULL;
776		}
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;
782			}
783
784			delete theVideoDescArray[i];
785			theVideoDescArray[i] = NULL;
786		}
787	}
788}
789
790uint32	STSDAtom::getMediaComponentSubType()
791{
792	return dynamic_cast<STBLAtom *>(getParent())->getMediaComponentSubType();
793}
794
795void STSDAtom::ReadSoundDescription()
796{
797	uint64 descBytesLeft;
798
799	SoundDescriptionV1 *aSoundDescriptionV1;
800
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);
806
807	aSoundDescriptionV1->VOLSize = 0;
808	aSoundDescriptionV1->theVOL = NULL;
809
810	// Read in Audio Sample Data
811	// We place into a V1 description even though it might be a V0 or earlier
812
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);
821
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));
827
828	} else {
829		// Calculate?
830		if (aSoundDescriptionV1->basefields.DataFormat == AUDIO_IMA4) {
831			aSoundDescriptionV1->samplesPerPacket = 64;
832			aSoundDescriptionV1->bytesPerFrame = aSoundDescriptionV1->desc.NoOfChannels * 34;
833
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;
841		}
842	}
843
844	// 0 means we dont have one
845	aSoundDescriptionV1->theWaveFormat.format_tag = 0;
846
847	descBytesLeft = getBytesRemaining();
848
849	while (descBytesLeft > 0) {
850
851		// More extended atoms
852		AtomBase *aAtomBase = getAtom(theStream);
853
854		aAtomBase->OnProcessMetaData();
855		printf("%s\n",aAtomBase->getAtomName());
856
857		if (dynamic_cast<WAVEAtom *>(aAtomBase)) {
858			// WAVE atom
859			aSoundDescriptionV1->theWaveFormat = dynamic_cast<WAVEAtom *>(aAtomBase)->getWaveFormat();
860		}
861
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);
867		}
868
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;
874		}
875
876		delete aAtomBase;
877	}
878
879	theAudioDescArray[0] = aSoundDescriptionV1;
880
881	PRINT(("Size:Format=%ld:%ld %Ld\n",aSoundDescriptionV1->basefields.Size,aSoundDescriptionV1->basefields.DataFormat,descBytesLeft));
882}
883
884void STSDAtom::ReadVideoDescription()
885{
886	uint64 descBytesLeft;
887
888	// read in Video Sample Data
889	VideoDescriptionV0 *aVideoDescription;
890
891	aVideoDescription = new VideoDescriptionV0;
892
893	Read(&aVideoDescription->basefields.Size);
894	Read(&aVideoDescription->basefields.DataFormat);
895	Read(aVideoDescription->basefields.Reserved,6);
896	Read(&aVideoDescription->basefields.DataReference);
897
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);
913
914	aVideoDescription->VOLSize = 0;
915	aVideoDescription->theVOL = NULL;
916
917	theVideoDescArray[0] = aVideoDescription;
918
919	descBytesLeft = getBytesRemaining();
920
921	// May be a VOL
922	// If not then seek back to where we are as it may be a complete new video description
923
924	if (descBytesLeft > 0) {
925
926		off_t pos = theStream->Position();
927		// More extended atoms
928		AtomBase *aAtomBase = getAtom(theStream);
929
930		aAtomBase->OnProcessMetaData();
931		printf("%s\n",aAtomBase->getAtomName());
932
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);
941		}
942
943		delete aAtomBase;
944	}
945
946	PRINT(("Size:Format=%ld:%ld %Ld\n",aVideoDescription->basefields.Size,aVideoDescription->basefields.DataFormat,getBytesRemaining()));
947}
948
949void STSDAtom::OnProcessMetaData()
950{
951	ReadArrayHeader(&theHeader);
952
953	for (uint32 i=0;i<theHeader.NoEntries;i++) {
954
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);
969
970				printf("%c%c%c%c\n",char(aSampleDescBase.DataFormat>>24),char(aSampleDescBase.DataFormat>>16),char(aSampleDescBase.DataFormat>>8),char(aSampleDescBase.DataFormat));
971
972				theStream->Seek(aSampleDescBase.Size - SampleDescBaseSize, SEEK_CUR);
973				break;
974		}
975	}
976}
977
978VideoDescriptionV0 STSDAtom::getAsVideo()
979{
980	// Assert IsVideo - how will we handle multiples
981	return *theVideoDescArray[0];
982}
983
984SoundDescriptionV1 STSDAtom::getAsAudio()
985{
986	// Assert IsAudio - how will we handle multiples
987	return *theAudioDescArray[0];
988}
989
990char *STSDAtom::OnGetAtomName()
991{
992	return "Sample Description Atom";
993}
994
995WAVEAtom::WAVEAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize) : AtomBase(pStream, pstreamOffset, patomType, patomSize)
996{
997}
998
999WAVEAtom::~WAVEAtom()
1000{
1001}
1002
1003void WAVEAtom::OnProcessMetaData()
1004{
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));
1013
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);
1021}
1022
1023char *WAVEAtom::OnGetAtomName()
1024{
1025	return "WAVE structure Atom";
1026}
1027
1028TMCDAtom::TMCDAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize) : AtomBase(pStream, pstreamOffset, patomType, patomSize)
1029{
1030}
1031
1032TMCDAtom::~TMCDAtom()
1033{
1034}
1035
1036void TMCDAtom::OnProcessMetaData()
1037{
1038}
1039
1040char *TMCDAtom::OnGetAtomName()
1041{
1042	return "TimeCode Atom";
1043}
1044
1045WIDEAtom::WIDEAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize) : AtomBase(pStream, pstreamOffset, patomType, patomSize)
1046{
1047}
1048
1049WIDEAtom::~WIDEAtom()
1050{
1051}
1052
1053void WIDEAtom::OnProcessMetaData()
1054{
1055}
1056
1057char *WIDEAtom::OnGetAtomName()
1058{
1059	return "WIDE Atom";
1060}
1061
1062FREEAtom::FREEAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize) : AtomBase(pStream, pstreamOffset, patomType, patomSize)
1063{
1064}
1065
1066FREEAtom::~FREEAtom()
1067{
1068}
1069
1070void FREEAtom::OnProcessMetaData()
1071{
1072}
1073
1074char *FREEAtom::OnGetAtomName()
1075{
1076	return "Free Atom";
1077}
1078
1079PNOTAtom::PNOTAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize) : AtomBase(pStream, pstreamOffset, patomType, patomSize)
1080{
1081}
1082
1083PNOTAtom::~PNOTAtom()
1084{
1085}
1086
1087void PNOTAtom::OnProcessMetaData()
1088{
1089}
1090
1091char *PNOTAtom::OnGetAtomName()
1092{
1093	return "Preview Atom";
1094}
1095
1096SKIPAtom::SKIPAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize) : AtomBase(pStream, pstreamOffset, patomType, patomSize)
1097{
1098}
1099
1100SKIPAtom::~SKIPAtom()
1101{
1102}
1103
1104void SKIPAtom::OnProcessMetaData()
1105{
1106}
1107
1108char *SKIPAtom::OnGetAtomName()
1109{
1110	return "Skip Atom";
1111}
1112
1113MDATAtom::MDATAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize) : AtomBase(pStream, pstreamOffset, patomType, patomSize)
1114{
1115}
1116
1117MDATAtom::~MDATAtom()
1118{
1119}
1120
1121void MDATAtom::OnProcessMetaData()
1122{
1123}
1124
1125char *MDATAtom::OnGetAtomName()
1126{
1127	return "Media Data Atom";
1128}
1129
1130off_t	MDATAtom::getEOF()
1131{
1132	return getStreamOffset() + getAtomSize();
1133}
1134
1135MINFAtom::MINFAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize) : AtomContainer(pStream, pstreamOffset, patomType, patomSize)
1136{
1137}
1138
1139MINFAtom::~MINFAtom()
1140{
1141}
1142
1143void MINFAtom::OnProcessMetaData()
1144{
1145}
1146
1147char *MINFAtom::OnGetAtomName()
1148{
1149	return "Quicktime Media Information Atom";
1150}
1151
1152uint32 MINFAtom::getMediaComponentSubType()
1153{
1154	return dynamic_cast<MDIAAtom *>(getParent())->getMediaComponentSubType();
1155}
1156
1157STBLAtom::STBLAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize) : AtomContainer(pStream, pstreamOffset, patomType, patomSize)
1158{
1159}
1160
1161STBLAtom::~STBLAtom()
1162{
1163}
1164
1165void STBLAtom::OnProcessMetaData()
1166{
1167}
1168
1169char *STBLAtom::OnGetAtomName()
1170{
1171	return "Quicktime Sample Table Atom";
1172}
1173
1174uint32 STBLAtom::getMediaComponentSubType()
1175{
1176	return dynamic_cast<MINFAtom *>(getParent())->getMediaComponentSubType();
1177}
1178
1179DINFAtom::DINFAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize) : AtomContainer(pStream, pstreamOffset, patomType, patomSize)
1180{
1181}
1182
1183DINFAtom::~DINFAtom()
1184{
1185}
1186
1187void DINFAtom::OnProcessMetaData()
1188{
1189}
1190
1191char *DINFAtom::OnGetAtomName()
1192{
1193	return "Quicktime Data Information Atom";
1194}
1195
1196TKHDAtom::TKHDAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize) : AtomBase(pStream, pstreamOffset, patomType, patomSize)
1197{
1198}
1199
1200TKHDAtom::~TKHDAtom()
1201{
1202}
1203
1204void TKHDAtom::OnProcessMetaData()
1205{
1206	Read(&Version);
1207
1208	if (Version == 0) {
1209		// Read into V0 header and convert to V1 Header
1210		tkhdV0 aHeaderV0;
1211
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);
1228
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;
1235
1236		for (uint32 i=0;i<36;i++) {
1237			theHeader.MatrixStructure[i] =  aHeaderV0.MatrixStructure[i];
1238		}
1239
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;
1250
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);
1269	}
1270
1271}
1272
1273char *TKHDAtom::OnGetAtomName()
1274{
1275	return "Quicktime Track Header";
1276}
1277
1278MDIAAtom::MDIAAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize) : AtomContainer(pStream, pstreamOffset, patomType, patomSize)
1279{
1280}
1281
1282MDIAAtom::~MDIAAtom()
1283{
1284}
1285
1286void MDIAAtom::OnProcessMetaData()
1287{
1288}
1289
1290char *MDIAAtom::OnGetAtomName()
1291{
1292	return "Quicktime Media Atom";
1293}
1294
1295uint32 MDIAAtom::getMediaComponentSubType()
1296{
1297	// get child atom hdlr
1298	HDLRAtom *aHDLRAtom;
1299	aHDLRAtom = dynamic_cast<HDLRAtom *>(GetChildAtom(uint32('hdlr')));
1300
1301	if (aHDLRAtom) {
1302		return aHDLRAtom->getMediaComponentSubType();
1303	}
1304
1305	return 0;
1306}
1307
1308MDHDAtom::MDHDAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize) : AtomBase(pStream, pstreamOffset, patomType, patomSize)
1309{
1310}
1311
1312MDHDAtom::~MDHDAtom()
1313{
1314}
1315
1316void MDHDAtom::OnProcessMetaData()
1317{
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);
1328}
1329
1330char *MDHDAtom::OnGetAtomName()
1331{
1332	return "Quicktime Media Header";
1333}
1334
1335bigtime_t	MDHDAtom::getDuration()
1336{
1337	return bigtime_t((uint64(theHeader.Duration) * 1000000L) / theHeader.TimeScale);
1338}
1339
1340uint32		MDHDAtom::getTimeScale()
1341{
1342	return theHeader.TimeScale;
1343}
1344
1345HDLRAtom::HDLRAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize) : AtomBase(pStream, pstreamOffset, patomType, patomSize)
1346{
1347}
1348
1349HDLRAtom::~HDLRAtom()
1350{
1351}
1352
1353void HDLRAtom::OnProcessMetaData()
1354{
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);
1364
1365	// Read Array of Strings?
1366}
1367
1368char *HDLRAtom::OnGetAtomName()
1369{
1370	return "Quicktime Handler Reference Atom ";
1371}
1372
1373bool HDLRAtom::IsVideoHandler()
1374{
1375	return (theHeader.ComponentSubType == 'vide');
1376}
1377
1378bool HDLRAtom::IsAudioHandler()
1379{
1380	return (theHeader.ComponentSubType == 'soun');
1381}
1382
1383uint32 HDLRAtom::getMediaComponentSubType()
1384{
1385	return theHeader.ComponentSubType;
1386}
1387
1388VMHDAtom::VMHDAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize) : AtomBase(pStream, pstreamOffset, patomType, patomSize)
1389{
1390}
1391
1392VMHDAtom::~VMHDAtom()
1393{
1394}
1395
1396void VMHDAtom::OnProcessMetaData()
1397{
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);
1407}
1408
1409char *VMHDAtom::OnGetAtomName()
1410{
1411	return "Quicktime Video Media Header";
1412}
1413
1414SMHDAtom::SMHDAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize) : AtomBase(pStream, pstreamOffset, patomType, patomSize)
1415{
1416}
1417
1418SMHDAtom::~SMHDAtom()
1419{
1420}
1421
1422void SMHDAtom::OnProcessMetaData()
1423{
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);
1431}
1432
1433char *SMHDAtom::OnGetAtomName()
1434{
1435	return "Quicktime Sound Media Header";
1436}
1437
1438FTYPAtom::FTYPAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize) : AtomBase(pStream, pstreamOffset, patomType, patomSize)
1439{
1440}
1441
1442FTYPAtom::~FTYPAtom()
1443{
1444}
1445
1446void FTYPAtom::OnProcessMetaData()
1447{
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)
1450
1451	Read(&major_brand);
1452	Read(&minor_version);
1453
1454	total_brands = getBytesRemaining() / sizeof(uint32);
1455
1456	if (total_brands > 32) {
1457		total_brands = 32;	// restrict to 32
1458	}
1459
1460	for (uint32 i=0;i<total_brands;i++) {
1461		Read(&compatable_brands[i]);
1462	}
1463}
1464
1465char *FTYPAtom::OnGetAtomName()
1466{
1467	return "Quicktime File Type";
1468}
1469
1470bool	FTYPAtom::HasBrand(uint32 brand)
1471{
1472	// return true if the specified brand is in the list
1473
1474	if (major_brand == brand) {
1475		return true;
1476	}
1477
1478	for (uint32 i=0;i<total_brands;i++) {
1479		if (compatable_brands[i] == brand) {
1480			return true;
1481		}
1482	}
1483
1484	return false;
1485}
1486