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 "MOVParser.h"
26
27TRAKAtom::TRAKAtom(BPositionIO *pStream, off_t pstreamOffset, uint32 patomType, uint64 patomSize) : AtomContainer(pStream, pstreamOffset, patomType, patomSize)
28{
29	theTKHDAtom = NULL;
30	theMDHDAtom = NULL;
31	framecount = 0;
32	bytespersample = 0;
33}
34
35TRAKAtom::~TRAKAtom()
36{
37}
38
39void TRAKAtom::OnProcessMetaData()
40{
41}
42
43char *TRAKAtom::OnGetAtomName()
44{
45	return "Quicktime Track Atom";
46}
47
48TKHDAtom	*TRAKAtom::getTKHDAtom()
49{
50	if (theTKHDAtom) {
51		return theTKHDAtom;
52	}
53
54	theTKHDAtom = dynamic_cast<TKHDAtom *>(GetChildAtom(uint32('tkhd'),0));
55
56	// Assert(theTKHDAtom != NULL,"Track has no Track Header");
57
58	return theTKHDAtom;
59}
60
61MDHDAtom	*TRAKAtom::getMDHDAtom()
62{
63	if (theMDHDAtom) {
64		return theMDHDAtom;
65	}
66
67	theMDHDAtom = dynamic_cast<MDHDAtom *>(GetChildAtom(uint32('mdhd'),0));
68
69	// Assert(theMDHDAtom != NULL,"Track has no Media Header");
70
71	return theMDHDAtom;
72}
73
74// Return duration of track
75bigtime_t	TRAKAtom::Duration(uint32 TimeScale)
76{
77	if (IsAudio() || IsVideo()) {
78		return getMDHDAtom()->getDuration();
79	}
80
81	return bigtime_t(getTKHDAtom()->getDuration() * 1000000L) / TimeScale;
82}
83
84void TRAKAtom::OnChildProcessingComplete()
85{
86	STTSAtom *aSTTSAtom = dynamic_cast<STTSAtom *>(GetChildAtom(uint32('stts'),0));
87
88	if (aSTTSAtom) {
89		framecount = aSTTSAtom->getSUMCounts();
90	}
91}
92
93// Is this a video track
94bool TRAKAtom::IsVideo()
95{
96	// video tracks have a vmhd atom
97	return (GetChildAtom(uint32('vmhd'),0) != NULL);
98}
99
100// Is this a audio track
101bool TRAKAtom::IsAudio()
102{
103	// audio tracks have a smhd atom
104	return (GetChildAtom(uint32('smhd'),0) != NULL);
105}
106
107uint32	TRAKAtom::getTimeForFrame(uint32 pFrame, uint32 pTimeScale)
108{
109	AtomBase *aAtomBase = GetChildAtom(uint32('stts'),0);
110
111	if (aAtomBase) {
112		STTSAtom *aSTTSAtom = dynamic_cast<STTSAtom *>(aAtomBase);
113
114		if (IsAudio()) {
115			// Frame * SampleRate = Time
116		} else if (IsVideo()) {
117			// Frame * fps = Time
118			return pFrame * ((aSTTSAtom->getSUMCounts() * 1000000L) / Duration(pTimeScale));
119		}
120	}
121
122	return 0;
123}
124
125uint32	TRAKAtom::getSampleForTime(uint32 pTime)
126{
127	AtomBase *aAtomBase = GetChildAtom(uint32('stts'),0);
128
129	if (aAtomBase) {
130		return (dynamic_cast<STTSAtom *>(aAtomBase))->getSampleForTime(pTime);
131	}
132
133	return 0;
134}
135
136uint32	TRAKAtom::getSampleForFrame(uint32 pFrame)
137{
138	AtomBase *aAtomBase = GetChildAtom(uint32('stts'),0);
139
140	if (aAtomBase) {
141		return (dynamic_cast<STTSAtom *>(aAtomBase))->getSampleForFrame(pFrame);
142	}
143
144	return 0;
145}
146
147uint32	TRAKAtom::getChunkForSample(uint32 pSample, uint32 *pOffsetInChunk)
148{
149	AtomBase *aAtomBase = GetChildAtom(uint32('stsc'),0);
150
151	if (aAtomBase) {
152		return (dynamic_cast<STSCAtom *>(aAtomBase))->getChunkForSample(pSample, pOffsetInChunk);
153	}
154
155	return 0;
156}
157
158uint32	TRAKAtom::getNoSamplesInChunk(uint32 pChunkID)
159{
160	AtomBase *aAtomBase = GetChildAtom(uint32('stsc'),0);
161
162	if (aAtomBase) {
163		return (dynamic_cast<STSCAtom *>(aAtomBase))->getNoSamplesInChunk(pChunkID);
164	}
165
166	return 0;
167}
168
169uint32	TRAKAtom::getSizeForSample(uint32 pSample)
170{
171	AtomBase *aAtomBase = GetChildAtom(uint32('stsz'),0);
172
173	if (aAtomBase) {
174		return (dynamic_cast<STSZAtom *>(aAtomBase))->getSizeForSample(pSample);
175	}
176
177	return 0;
178}
179
180uint64	TRAKAtom::getOffsetForChunk(uint32 pChunkID)
181{
182	AtomBase *aAtomBase = GetChildAtom(uint32('stco'),0);
183
184	if (aAtomBase) {
185		return (dynamic_cast<STCOAtom *>(aAtomBase))->getOffsetForChunk(pChunkID);
186	}
187
188	return 0;
189}
190
191uint32	TRAKAtom::getFirstSampleInChunk(uint32 pChunkID)
192{
193	AtomBase *aAtomBase = GetChildAtom(uint32('stsc'),0);
194
195	if (aAtomBase) {
196		return (dynamic_cast<STSCAtom *>(aAtomBase))->getFirstSampleInChunk(pChunkID);
197	}
198
199	return 0;
200}
201
202
203bool	TRAKAtom::IsSyncSample(uint32 pSampleNo)
204{
205	AtomBase *aAtomBase = GetChildAtom(uint32('stss'),0);
206
207	if (aAtomBase) {
208		return (dynamic_cast<STSSAtom *>(aAtomBase))->IsSyncSample(pSampleNo);
209	}
210
211	return false;
212}
213
214bool	TRAKAtom::IsSingleSampleSize()
215{
216	AtomBase *aAtomBase = GetChildAtom(uint32('stsz'),0);
217
218	if (aAtomBase) {
219		return (dynamic_cast<STSZAtom *>(aAtomBase))->IsSingleSampleSize();
220	}
221
222	return false;
223}
224
225bool	TRAKAtom::IsActive()
226{
227	return getTKHDAtom()->IsActive();
228}
229
230uint32	TRAKAtom::getBytesPerSample()
231{
232AtomBase *aAtomBase;
233
234	if (bytespersample > 0) {
235		return bytespersample;
236	}
237
238	// calculate bytes per sample and cache it
239
240	if (IsAudio()) {
241		// only used by Audio
242		aAtomBase = GetChildAtom(uint32('stsd'),0);
243		if (aAtomBase) {
244			STSDAtom *aSTSDAtom = dynamic_cast<STSDAtom *>(aAtomBase);
245
246			SoundDescriptionV1 aSoundDescription = aSTSDAtom->getAsAudio();
247
248			bytespersample = aSoundDescription.bytesPerSample;
249		}
250	}
251
252	return bytespersample;
253}
254
255uint32	TRAKAtom::getTotalChunks()
256{
257	AtomBase *aAtomBase = GetChildAtom(uint32('stco'),0);
258
259	if (aAtomBase) {
260		return (dynamic_cast<STCOAtom *>(aAtomBase))->getTotalChunks();
261	}
262
263	return 0;
264}
265
266// GetAudioMetaData()	// If this is a audio track get the audio meta data
267// GetVideoMetaData()	// If this is a video track get the video meta data
268