1 /*****************************************************************
2 |
3 | AP4 - Fragment Based Sample Tables
4 |
5 | Copyright 2002-2009 Axiomatic Systems, LLC
6 |
7 |
8 | This atom is part of AP4 (MP4 Audio Processing Library).
9 |
10 | Unless you have obtained Bento4 under a difference license,
11 | this version of Bento4 is Bento4|GPL.
12 | Bento4|GPL is free software; you can redistribute it and/or modify
13 | it under the terms of the GNU General Public License as published by
14 | the Free Software Foundation; either version 2, or (at your option)
15 | any later version.
16 |
17 | Bento4|GPL is distributed in the hope that it will be useful,
18 | but WITHOUT ANY WARRANTY; without even the implied warranty of
19 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 | GNU General Public License for more details.
21 |
22 | You should have received a copy of the GNU General Public License
23 | along with Bento4|GPL; see the atom COPYING. If not, write to the
24 | Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
25 | 02111-1307, USA.
26 |
27 ****************************************************************/
28
29 /*----------------------------------------------------------------------
30 | includes
31 +---------------------------------------------------------------------*/
32 #include "Ap4FragmentSampleTable.h"
33 #include "Ap4ByteStream.h"
34 #include "Ap4Sample.h"
35 #include "Ap4TrexAtom.h"
36 #include "Ap4TfhdAtom.h"
37 #include "Ap4ContainerAtom.h"
38 #include "Ap4TrunAtom.h"
39 #include "Ap4TfdtAtom.h"
40 #include "Ap4MovieFragment.h"
41
42 /*----------------------------------------------------------------------
43 | AP4_FragmentSampleTable::AP4_FragmentSampleTable
44 +---------------------------------------------------------------------*/
AP4_FragmentSampleTable(AP4_ContainerAtom * traf,AP4_TrexAtom * trex,AP4_Cardinal internal_track_id,AP4_ByteStream * sample_stream,AP4_Position moof_offset,AP4_Position mdat_payload_offset,AP4_UI64 mdat_payload_size,AP4_UI64 dts_origin)45 AP4_FragmentSampleTable::AP4_FragmentSampleTable(AP4_ContainerAtom* traf,
46 AP4_TrexAtom* trex,
47 AP4_Cardinal internal_track_id,
48 AP4_ByteStream* sample_stream,
49 AP4_Position moof_offset,
50 AP4_Position mdat_payload_offset,
51 AP4_UI64 mdat_payload_size,
52 AP4_UI64 dts_origin)
53 : m_Duration(0)
54 , m_InternalTrackId(internal_track_id)
55 {
56 AP4_TfhdAtom* tfhd = AP4_DYNAMIC_CAST(AP4_TfhdAtom, traf->GetChild(AP4_ATOM_TYPE_TFHD));
57 if (tfhd == NULL) return;
58
59 // count all the samples and reserve space for them
60 unsigned int sample_count = 0;
61 for (AP4_List<AP4_Atom>::Item* item = traf->GetChildren().FirstItem();
62 item;
63 item = item->GetNext()) {
64 AP4_Atom* atom = item->GetData();
65 if (atom->GetType() == AP4_ATOM_TYPE_TRUN) {
66 AP4_TrunAtom* trun = AP4_DYNAMIC_CAST(AP4_TrunAtom, atom);
67 if (trun) sample_count += trun->GetEntries().ItemCount();
68 }
69 }
70 m_Samples.EnsureCapacity(sample_count);
71
72 // check if we have a timecode base
73 AP4_TfdtAtom* tfdt = AP4_DYNAMIC_CAST(AP4_TfdtAtom, traf->GetChild(AP4_ATOM_TYPE_TFDT));
74 if (tfdt) {
75 dts_origin = tfdt->GetBaseMediaDecodeTime();
76 }
77
78 // process all the trun atoms
79 AP4_UI32 trun_flags(0);
80 for (AP4_List<AP4_Atom>::Item* item = traf->GetChildren().FirstItem();
81 item;
82 item = item->GetNext()) {
83 AP4_Atom* atom = item->GetData();
84 if (atom->GetType() == AP4_ATOM_TYPE_TRUN) {
85 AP4_TrunAtom* trun = AP4_DYNAMIC_CAST(AP4_TrunAtom, atom);
86 if (trun) {
87 AP4_Result result = AddTrun(trun,
88 tfhd,
89 trex,
90 sample_stream,
91 moof_offset,
92 mdat_payload_offset,
93 dts_origin);
94 if (AP4_FAILED(result)) return;
95 trun_flags |= trun->GetFlags();
96 }
97 }
98 }
99 // Hack if we have a single sample and default sample size is wrong (hbo ttml)
100 if (m_Samples.ItemCount() == 1 && (trun_flags & AP4_TRUN_FLAG_SAMPLE_SIZE_PRESENT) == 0)
101 m_Samples[0].SetSize(mdat_payload_size);
102 }
103
104 /*----------------------------------------------------------------------
105 | AP4_FragmentSampleTable::~AP4_FragmentSampleTable
106 +---------------------------------------------------------------------*/
~AP4_FragmentSampleTable()107 AP4_FragmentSampleTable::~AP4_FragmentSampleTable()
108 {
109 }
110
111 /*----------------------------------------------------------------------
112 | AP4_FragmentSampleTable::AddTrun
113 +---------------------------------------------------------------------*/
114 AP4_Result
AddTrun(AP4_TrunAtom * trun,AP4_TfhdAtom * tfhd,AP4_TrexAtom * trex,AP4_ByteStream * sample_stream,AP4_Position moof_offset,AP4_Position & payload_offset,AP4_UI64 & dts_origin)115 AP4_FragmentSampleTable::AddTrun(AP4_TrunAtom* trun,
116 AP4_TfhdAtom* tfhd,
117 AP4_TrexAtom* trex,
118 AP4_ByteStream* sample_stream,
119 AP4_Position moof_offset,
120 AP4_Position& payload_offset,
121 AP4_UI64& dts_origin)
122 {
123 AP4_Flags tfhd_flags = tfhd->GetFlags();
124 AP4_Flags trun_flags = trun->GetFlags();
125
126 // update the number of samples
127 unsigned int start = m_Samples.ItemCount();
128 m_Samples.SetItemCount(start + trun->GetEntries().ItemCount());
129
130 // base data offset
131 AP4_Position data_offset = 0;
132 if (tfhd_flags & AP4_TFHD_FLAG_BASE_DATA_OFFSET_PRESENT) {
133 data_offset = tfhd->GetBaseDataOffset();
134 } else {
135 data_offset = moof_offset;
136 }
137 if (trun_flags & AP4_TRUN_FLAG_DATA_OFFSET_PRESENT) {
138 data_offset += trun->GetDataOffset();
139 }
140 // MS hack
141 if (data_offset < payload_offset) {
142 data_offset = payload_offset;
143 } else {
144 payload_offset = data_offset;
145 }
146
147 // sample description index
148 AP4_UI32 sample_description_index = 0;
149 if (tfhd_flags & AP4_TFHD_FLAG_SAMPLE_DESCRIPTION_INDEX_PRESENT) {
150 sample_description_index = tfhd->GetSampleDescriptionIndex();
151 } else if (trex) {
152 sample_description_index = trex->GetDefaultSampleDescriptionIndex();
153 }
154
155 // default sample size
156 AP4_UI32 default_sample_size = 0;
157 if (tfhd_flags & AP4_TFHD_FLAG_DEFAULT_SAMPLE_SIZE_PRESENT) {
158 default_sample_size = tfhd->GetDefaultSampleSize();
159 } else if (trex) {
160 default_sample_size = trex->GetDefaultSampleSize();
161 }
162
163 // default sample duration
164 AP4_UI32 default_sample_duration = 0;
165 if (tfhd_flags & AP4_TFHD_FLAG_DEFAULT_SAMPLE_DURATION_PRESENT) {
166 default_sample_duration = tfhd->GetDefaultSampleDuration();
167 } else if (trex) {
168 default_sample_duration = trex->GetDefaultSampleDuration();
169 }
170
171 // default sample flags
172 AP4_UI32 default_sample_flags = 0;
173 if (tfhd_flags & AP4_TFHD_FLAG_DEFAULT_SAMPLE_FLAGS_PRESENT) {
174 default_sample_flags = tfhd->GetDefaultSampleFlags();
175 } else if (trex) {
176 default_sample_flags = trex->GetDefaultSampleFlags();
177 }
178
179 // parse all trun entries to setup the samples
180 AP4_UI64 dts = dts_origin;
181 m_Duration = 0;
182 for (unsigned int i=0; i<trun->GetEntries().ItemCount(); i++) {
183 const AP4_TrunAtom::Entry& entry = trun->GetEntries()[i];
184 AP4_Sample& sample = m_Samples[start+i];
185
186 // sample size
187 if (trun_flags & AP4_TRUN_FLAG_SAMPLE_SIZE_PRESENT) {
188 sample.SetSize(entry.sample_size);
189 } else {
190 sample.SetSize(default_sample_size);
191 }
192 payload_offset += sample.GetSize(); // update the payload offset
193
194 // sample duration
195 if (trun_flags & AP4_TRUN_FLAG_SAMPLE_DURATION_PRESENT) {
196 sample.SetDuration(entry.sample_duration);
197 } else {
198 sample.SetDuration(default_sample_duration);
199 }
200
201 // sample flags
202 AP4_UI32 sample_flags = default_sample_flags;
203 if (i==0 && (trun_flags & AP4_TRUN_FLAG_FIRST_SAMPLE_FLAGS_PRESENT)) {
204 sample_flags = trun->GetFirstSampleFlags();
205 } else if (trun_flags & AP4_TRUN_FLAG_SAMPLE_FLAGS_PRESENT) {
206 sample_flags = entry.sample_flags;
207 }
208 if ((sample_flags & AP4_FRAG_FLAG_SAMPLE_IS_DIFFERENCE) == 0) {
209 sample.SetSync(true);
210 } else {
211 sample.SetSync(false);
212 }
213
214 // sample description index
215 if (sample_description_index >= 1) {
216 sample.SetDescriptionIndex(sample_description_index-1);
217 }
218
219 // data stream
220 if (sample_stream) sample.SetDataStream(*sample_stream);
221
222 // data offset
223 sample.SetOffset(data_offset);
224 data_offset += sample.GetSize();
225
226 // dts and cts
227 sample.SetDts(dts);
228 if (trun_flags & AP4_TRUN_FLAG_SAMPLE_COMPOSITION_TIME_OFFSET_PRESENT) {
229 sample.SetCtsDelta(entry.sample_composition_time_offset);
230 }
231
232 // update the counters
233 dts += sample.GetDuration();
234 m_Duration += sample.GetDuration();
235 }
236
237 // update the dts
238 dts_origin = dts;
239
240 return AP4_SUCCESS;
241 }
242
243 /*----------------------------------------------------------------------
244 | AP4_FragmentSampleTable::GetSample
245 +---------------------------------------------------------------------*/
246 AP4_Result
GetSample(AP4_Ordinal index,AP4_Sample & sample)247 AP4_FragmentSampleTable::GetSample(AP4_Ordinal index,
248 AP4_Sample& sample)
249 {
250 if (index >= m_Samples.ItemCount()) return AP4_ERROR_OUT_OF_RANGE;
251
252 // copy the sample
253 sample = m_Samples[index];
254
255 return AP4_SUCCESS;
256 }
257
258 /*----------------------------------------------------------------------
259 | AP4_FragmentSampleTable::GetSampleCount
260 +---------------------------------------------------------------------*/
261 AP4_Cardinal
GetSampleCount()262 AP4_FragmentSampleTable::GetSampleCount()
263 {
264 return m_Samples.ItemCount();
265 }
266
267 /*----------------------------------------------------------------------
268 | AP4_FragmentSampleTable::GetSampleDescription
269 +---------------------------------------------------------------------*/
270 AP4_SampleDescription*
GetSampleDescription(AP4_Ordinal)271 AP4_FragmentSampleTable::GetSampleDescription(AP4_Ordinal /*index*/)
272 {
273 return NULL; // FIXME
274 }
275
276 /*----------------------------------------------------------------------
277 | AP4_FragmentSampleTable::GetSampleDescriptionCount
278 +---------------------------------------------------------------------*/
279 AP4_Cardinal
GetSampleDescriptionCount()280 AP4_FragmentSampleTable::GetSampleDescriptionCount()
281 {
282 return 1; // FIXME
283 }
284
285 /*----------------------------------------------------------------------
286 | AP4_AtomSampleTable::GetSampleChunkPosition
287 +---------------------------------------------------------------------*/
288 AP4_Result
GetSampleChunkPosition(AP4_Ordinal sample_index,AP4_Ordinal & chunk_index,AP4_Ordinal & position_in_chunk)289 AP4_FragmentSampleTable::GetSampleChunkPosition(AP4_Ordinal sample_index,
290 AP4_Ordinal& chunk_index,
291 AP4_Ordinal& position_in_chunk)
292 {
293 chunk_index = 0;
294 position_in_chunk = sample_index;
295
296 return AP4_SUCCESS;
297 }
298
299 /*----------------------------------------------------------------------
300 | AP4_FragmentSampleTable::GetSampleIndexForTimeStamp
301 +---------------------------------------------------------------------*/
302 AP4_Result
GetSampleIndexForTimeStamp(AP4_UI64 ts,AP4_Ordinal & sample_index)303 AP4_FragmentSampleTable::GetSampleIndexForTimeStamp(AP4_UI64 ts,
304 AP4_Ordinal& sample_index)
305 {
306 if (!m_Samples.ItemCount())
307 return AP4_ERROR_NOT_ENOUGH_DATA;
308
309 sample_index = 0;
310 while (sample_index < m_Samples.ItemCount() && m_Samples[sample_index].GetCts() + m_Samples[sample_index].GetDuration() < ts)
311 ++sample_index;
312
313 if (sample_index == m_Samples.ItemCount())
314 return AP4_ERROR_NOT_ENOUGH_DATA;
315
316 return AP4_SUCCESS;
317 }
318
319 /*----------------------------------------------------------------------
320 | AP4_FragmentSampleTable::GetNearestSyncSampleIndex
321 +---------------------------------------------------------------------*/
322 AP4_Ordinal
GetNearestSyncSampleIndex(AP4_Ordinal sample_index,bool before)323 AP4_FragmentSampleTable::GetNearestSyncSampleIndex(AP4_Ordinal sample_index, bool before)
324 {
325 if (sample_index >= m_Samples.ItemCount())
326 return sample_index;
327
328 AP4_Ordinal end(before ? 0 : m_Samples.ItemCount());
329
330 while (sample_index != end && !m_Samples[sample_index].IsSync())
331 sample_index = sample_index + (before ? -1 : 1);
332
333 return sample_index;
334 }
335
336