1 /*
2 ** FAAD2 - Freeware Advanced Audio (AAC) Decoder including SBR decoding
3 ** Copyright (C) 2003-2005 M. Bakker, Nero AG, http://www.nero.com
4 **
5 ** This program is free software; you can redistribute it and/or modify
6 ** it under the terms of the GNU General Public License as published by
7 ** the Free Software Foundation; either version 2 of the License, or
8 ** (at your option) any later version.
9 **
10 ** This program is distributed in the hope that it will be useful,
11 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 ** GNU General Public License for more details.
14 **
15 ** You should have received a copy of the GNU General Public License
16 ** along with this program; if not, write to the Free Software
17 ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 **
19 ** Any non-GPL usage of this software or parts of this software is strictly
20 ** forbidden.
21 **
22 ** The "appropriate copyright message" mentioned in section 2c of the GPLv2
23 ** must read: "Code from FAAD2 is copyright (c) Nero AG, www.nero.com"
24 **
25 ** Commercial non-GPL licensing of this software is possible.
26 ** For more info contact Nero AG through Mpeg4AAClicense@nero.com.
27 **
28 ** $Id: mp4atom.c,v 1.29 2009/01/19 23:56:30 menno Exp $
29 **/
30
31 #include <stdlib.h>
32 #ifndef _WIN32
33 #include "config.h"
34 #else
35 #include <tchar.h>
36 #include <windows.h>
37 #endif
38 #ifdef HAVE_GETPWUID
39 # include <pwd.h>
40 #endif
41 #ifdef HAVE_STRING_H
42 # include <string.h>
43 #endif
44 #include "mp4ffint.h"
45 #include <stdio.h>
46
47 //#define trace(...) { fprintf(stderr, __VA_ARGS__); }
48 #define trace(fmt,...)
49 #define min(x,y) ((x)<(y)?(x):(y))
50
51 #define COPYRIGHT_SYMBOL ((int8_t)0xA9)
52
53 /* parse atom header size */
mp4ff_atom_get_size(const int8_t * data)54 static int32_t mp4ff_atom_get_size(const int8_t *data)
55 {
56 uint32_t result;
57 uint32_t a, b, c, d;
58
59 a = (uint8_t)data[0];
60 b = (uint8_t)data[1];
61 c = (uint8_t)data[2];
62 d = (uint8_t)data[3];
63
64 result = (a<<24) | (b<<16) | (c<<8) | d;
65 //if (result > 0 && result < 8) result = 8;
66
67 return (int32_t)result;
68 }
69
70 /* comnapre 2 atom names, returns 1 for equal, 0 for unequal */
mp4ff_atom_compare(const int8_t a1,const int8_t b1,const int8_t c1,const int8_t d1,const int8_t a2,const int8_t b2,const int8_t c2,const int8_t d2)71 static int32_t mp4ff_atom_compare(const int8_t a1, const int8_t b1, const int8_t c1, const int8_t d1,
72 const int8_t a2, const int8_t b2, const int8_t c2, const int8_t d2)
73 {
74 if (a1 == a2 && b1 == b2 && c1 == c2 && d1 == d2)
75 return 1;
76 else
77 return 0;
78 }
79
mp4ff_atom_name_to_type(const int8_t a,const int8_t b,const int8_t c,const int8_t d)80 static uint8_t mp4ff_atom_name_to_type(const int8_t a, const int8_t b,
81 const int8_t c, const int8_t d)
82 {
83 if (a == 'm')
84 {
85 if (mp4ff_atom_compare(a,b,c,d, 'm','o','o','v'))
86 return ATOM_MOOV;
87 else if (mp4ff_atom_compare(a,b,c,d, 'm','i','n','f'))
88 return ATOM_MINF;
89 else if (mp4ff_atom_compare(a,b,c,d, 'm','d','i','a'))
90 return ATOM_MDIA;
91 else if (mp4ff_atom_compare(a,b,c,d, 'm','d','a','t'))
92 return ATOM_MDAT;
93 else if (mp4ff_atom_compare(a,b,c,d, 'm','d','h','d'))
94 return ATOM_MDHD;
95 else if (mp4ff_atom_compare(a,b,c,d, 'm','v','h','d'))
96 return ATOM_MVHD;
97 else if (mp4ff_atom_compare(a,b,c,d, 'm','p','4','a'))
98 return ATOM_MP4A;
99 else if (mp4ff_atom_compare(a,b,c,d, 'm','p','4','v'))
100 return ATOM_MP4V;
101 else if (mp4ff_atom_compare(a,b,c,d, 'm','p','4','s'))
102 return ATOM_MP4S;
103 else if (mp4ff_atom_compare(a,b,c,d, 'm','e','t','a'))
104 return ATOM_META;
105 } else if (a == 't') {
106 if (mp4ff_atom_compare(a,b,c,d, 't','r','a','k'))
107 return ATOM_TRAK;
108 else if (mp4ff_atom_compare(a,b,c,d, 't','k','h','d'))
109 return ATOM_TKHD;
110 else if (mp4ff_atom_compare(a,b,c,d, 't','r','e','f'))
111 return ATOM_TREF;
112 else if (mp4ff_atom_compare(a,b,c,d, 't','r','k','n'))
113 return ATOM_TRACK;
114 else if (mp4ff_atom_compare(a,b,c,d, 't','m','p','o'))
115 return ATOM_TEMPO;
116 else if (mp4ff_atom_compare(a,b,c,d, 't','v','n','n'))
117 return ATOM_NETWORK;
118 else if (mp4ff_atom_compare(a,b,c,d, 't','v','s','h'))
119 return ATOM_SHOW;
120 else if (mp4ff_atom_compare(a,b,c,d, 't','v','e','n'))
121 return ATOM_EPISODENAME;
122 else if (mp4ff_atom_compare(a,b,c,d, 't','v','s','n'))
123 return ATOM_SEASON;
124 else if (mp4ff_atom_compare(a,b,c,d, 't','v','e','s'))
125 return ATOM_EPISODE;
126 } else if (a == 's') {
127 if (mp4ff_atom_compare(a,b,c,d, 's','t','b','l'))
128 return ATOM_STBL;
129 else if (mp4ff_atom_compare(a,b,c,d, 's','m','h','d'))
130 return ATOM_SMHD;
131 else if (mp4ff_atom_compare(a,b,c,d, 's','t','s','d'))
132 return ATOM_STSD;
133 else if (mp4ff_atom_compare(a,b,c,d, 's','t','t','s'))
134 return ATOM_STTS;
135 else if (mp4ff_atom_compare(a,b,c,d, 's','t','c','o'))
136 return ATOM_STCO;
137 else if (mp4ff_atom_compare(a,b,c,d, 'c','o','6','4'))
138 return ATOM_STCO;
139 else if (mp4ff_atom_compare(a,b,c,d, 's','t','s','c'))
140 return ATOM_STSC;
141 else if (mp4ff_atom_compare(a,b,c,d, 's','t','s','z'))
142 return ATOM_STSZ;
143 else if (mp4ff_atom_compare(a,b,c,d, 's','t','z','2'))
144 return ATOM_STZ2;
145 else if (mp4ff_atom_compare(a,b,c,d, 's','k','i','p'))
146 return ATOM_SKIP;
147 else if (mp4ff_atom_compare(a,b,c,d, 's','i','n','f'))
148 return ATOM_SINF;
149 else if (mp4ff_atom_compare(a,b,c,d, 's','c','h','i'))
150 return ATOM_SCHI;
151 else if (mp4ff_atom_compare(a,b,c,d, 's','o','n','m'))
152 return ATOM_SORTTITLE;
153 else if (mp4ff_atom_compare(a,b,c,d, 's','o','a','l'))
154 return ATOM_SORTALBUM;
155 else if (mp4ff_atom_compare(a,b,c,d, 's','o','a','r'))
156 return ATOM_SORTARTIST;
157 else if (mp4ff_atom_compare(a,b,c,d, 's','o','a','a'))
158 return ATOM_SORTALBUMARTIST;
159 else if (mp4ff_atom_compare(a,b,c,d, 's','o','c','o'))
160 return ATOM_SORTWRITER;
161 else if (mp4ff_atom_compare(a,b,c,d, 's','o','s','n'))
162 return ATOM_SORTSHOW;
163 } else if (a == COPYRIGHT_SYMBOL) {
164 if (mp4ff_atom_compare(a,b,c,d, COPYRIGHT_SYMBOL,'n','a','m'))
165 return ATOM_TITLE;
166 else if (mp4ff_atom_compare(a,b,c,d, COPYRIGHT_SYMBOL,'A','R','T'))
167 return ATOM_ARTIST;
168 else if (mp4ff_atom_compare(a,b,c,d, COPYRIGHT_SYMBOL,'w','r','t'))
169 return ATOM_WRITER;
170 else if (mp4ff_atom_compare(a,b,c,d, COPYRIGHT_SYMBOL,'a','l','b'))
171 return ATOM_ALBUM;
172 else if (mp4ff_atom_compare(a,b,c,d, COPYRIGHT_SYMBOL,'d','a','y'))
173 return ATOM_DATE;
174 else if (mp4ff_atom_compare(a,b,c,d, COPYRIGHT_SYMBOL,'t','o','o'))
175 return ATOM_TOOL;
176 else if (mp4ff_atom_compare(a,b,c,d, COPYRIGHT_SYMBOL,'c','m','t'))
177 return ATOM_COMMENT;
178 else if (mp4ff_atom_compare(a,b,c,d, COPYRIGHT_SYMBOL,'g','e','n'))
179 return ATOM_GENRE1;
180 else if (mp4ff_atom_compare(a,b,c,d, COPYRIGHT_SYMBOL,'g','r','p'))
181 return ATOM_CONTENTGROUP;
182 else if (mp4ff_atom_compare(a,b,c,d, COPYRIGHT_SYMBOL,'l','y','r'))
183 return ATOM_LYRICS;
184 }
185
186 if (mp4ff_atom_compare(a,b,c,d, 'e','d','t','s'))
187 return ATOM_EDTS;
188 else if (mp4ff_atom_compare(a,b,c,d, 'e','s','d','s'))
189 return ATOM_ESDS;
190 else if (mp4ff_atom_compare(a,b,c,d, 'f','t','y','p'))
191 return ATOM_FTYP;
192 else if (mp4ff_atom_compare(a,b,c,d, 'f','r','e','e'))
193 return ATOM_FREE;
194 else if (mp4ff_atom_compare(a,b,c,d, 'h','m','h','d'))
195 return ATOM_HMHD;
196 else if (mp4ff_atom_compare(a,b,c,d, 'v','m','h','d'))
197 return ATOM_VMHD;
198 else if (mp4ff_atom_compare(a,b,c,d, 'u','d','t','a'))
199 return ATOM_UDTA;
200 else if (mp4ff_atom_compare(a,b,c,d, 'i','l','s','t'))
201 return ATOM_ILST;
202 else if (mp4ff_atom_compare(a,b,c,d, 'n','a','m','e'))
203 return ATOM_NAME;
204 else if (mp4ff_atom_compare(a,b,c,d, 'd','a','t','a'))
205 return ATOM_DATA;
206 else if (mp4ff_atom_compare(a,b,c,d, 'd','i','s','k'))
207 return ATOM_DISC;
208 else if (mp4ff_atom_compare(a,b,c,d, 'g','n','r','e'))
209 return ATOM_GENRE2;
210 else if (mp4ff_atom_compare(a,b,c,d, 'c','o','v','r'))
211 return ATOM_COVER;
212 else if (mp4ff_atom_compare(a,b,c,d, 'c','p','i','l'))
213 return ATOM_COMPILATION;
214 else if (mp4ff_atom_compare(a,b,c,d, 'c','t','t','s'))
215 return ATOM_CTTS;
216 else if (mp4ff_atom_compare(a,b,c,d, 'd','r','m','s'))
217 return ATOM_DRMS;
218 else if (mp4ff_atom_compare(a,b,c,d, 'f','r','m','a'))
219 return ATOM_FRMA;
220 else if (mp4ff_atom_compare(a,b,c,d, 'p','r','i','v'))
221 return ATOM_PRIV;
222 else if (mp4ff_atom_compare(a,b,c,d, 'i','v','i','v'))
223 return ATOM_IVIV;
224 else if (mp4ff_atom_compare(a,b,c,d, 'u','s','e','r'))
225 return ATOM_USER;
226 else if (mp4ff_atom_compare(a,b,c,d, 'k','e','y',' '))
227 return ATOM_KEY;
228 else if (mp4ff_atom_compare(a,b,c,d, 'a','A','R','T'))
229 return ATOM_ALBUM_ARTIST;
230 else if (mp4ff_atom_compare(a,b,c,d, 'd','e','s','c'))
231 return ATOM_DESCRIPTION;
232 else if (mp4ff_atom_compare(a,b,c,d, 'p','c','s','t'))
233 return ATOM_PODCAST;
234 else if (mp4ff_atom_compare(a,b,c,d, '-','-','-','-'))
235 return ATOM_CUSTOM;
236 else if (mp4ff_atom_compare(a,b,c,d, 'c','h','p','l'))
237 return ATOM_CHPL;
238 else if (mp4ff_atom_compare(a,b,c,d, 'c','h','a','p'))
239 return ATOM_CHAP;
240 else if (mp4ff_atom_compare(a,b,c,d, 't','e','x','t'))
241 return ATOM_TEXT;
242 else if (mp4ff_atom_compare(a,b,c,d, 's','u','b','p'))
243 return ATOM_TEXT;
244 else if (mp4ff_atom_compare(a,b,c,d, 't','x','3','g'))
245 return ATOM_TEXT;
246 else if (mp4ff_atom_compare(a,b,c,d, 's','b','t','l'))
247 return ATOM_TEXT;
248 else if (mp4ff_atom_compare(a,b,c,d, 'e','l','s','t'))
249 return ATOM_ELST;
250 else
251 return ATOM_UNKNOWN;
252 }
253
254 /* read atom header, return atom size, atom size is with header included */
mp4ff_atom_read_header(mp4ff_t * f,uint8_t * atom_type,uint8_t * header_size)255 uint64_t mp4ff_atom_read_header(mp4ff_t *f, uint8_t *atom_type, uint8_t *header_size)
256 {
257 uint64_t size;
258 int32_t ret;
259 int8_t atom_header[8];
260
261 ret = mp4ff_read_data(f, atom_header, 8);
262 if (ret != 8)
263 return 0;
264
265 size = mp4ff_atom_get_size(atom_header);
266 *header_size = 8;
267
268 /* check for 64 bit atom size */
269 if (size == 1)
270 {
271 *header_size = 16;
272 size = mp4ff_read_int64(f);
273 }
274
275 // printf("%c%c%c%c\n", atom_header[4], atom_header[5], atom_header[6], atom_header[7]);
276
277 *atom_type = mp4ff_atom_name_to_type(atom_header[4], atom_header[5], atom_header[6], atom_header[7]);
278
279 return size;
280 }
281
mp4ff_read_stsz(mp4ff_t * f)282 static int32_t mp4ff_read_stsz(mp4ff_t *f)
283 {
284 trace ("mp4ff_read_stsz\n");
285 mp4ff_read_char(f); /* version */
286 mp4ff_read_int24(f); /* flags */
287 f->track[f->total_tracks - 1]->stsz_sample_size = mp4ff_read_int32(f);
288 f->track[f->total_tracks - 1]->stsz_sample_count = mp4ff_read_int32(f);
289
290 if (f->track[f->total_tracks - 1]->stsz_sample_size == 0)
291 {
292 int32_t i;
293 f->track[f->total_tracks - 1]->stsz_table = (int32_t*)malloc(f->track[f->total_tracks - 1]->stsz_sample_count*sizeof(int32_t));
294
295 for (i = 0; i < f->track[f->total_tracks - 1]->stsz_sample_count; i++)
296 {
297 f->track[f->total_tracks - 1]->stsz_table[i] = mp4ff_read_int32(f);
298 }
299 }
300
301 return 0;
302 }
303
mp4ff_read_esds(mp4ff_t * f)304 static int32_t mp4ff_read_esds(mp4ff_t *f)
305 {
306 uint8_t tag;
307 uint32_t temp;
308
309 mp4ff_read_char(f); /* version */
310 mp4ff_read_int24(f); /* flags */
311
312 /* get and verify ES_DescrTag */
313 tag = mp4ff_read_char(f);
314 if (tag == 0x03)
315 {
316 /* read length */
317 if (mp4ff_read_mp4_descr_length(f) < 5 + 15)
318 {
319 return 1;
320 }
321 /* skip 3 bytes */
322 mp4ff_read_int24(f);
323 } else {
324 /* skip 2 bytes */
325 mp4ff_read_int16(f);
326 }
327
328 /* get and verify DecoderConfigDescrTab */
329 if (mp4ff_read_char(f) != 0x04)
330 {
331 return 1;
332 }
333
334 /* read length */
335 temp = mp4ff_read_mp4_descr_length(f);
336 if (temp < 13) return 1;
337
338 f->track[f->total_tracks - 1]->audioType = mp4ff_read_char(f);
339 mp4ff_read_int32(f);//0x15000414 ????
340 f->track[f->total_tracks - 1]->maxBitrate = mp4ff_read_int32(f);
341 f->track[f->total_tracks - 1]->avgBitrate = mp4ff_read_int32(f);
342
343 /* get and verify DecSpecificInfoTag */
344 if (mp4ff_read_char(f) != 0x05)
345 {
346 return 1;
347 }
348
349 /* read length */
350 f->track[f->total_tracks - 1]->decoderConfigLen = mp4ff_read_mp4_descr_length(f);
351
352 if (f->track[f->total_tracks - 1]->decoderConfig)
353 free(f->track[f->total_tracks - 1]->decoderConfig);
354 f->track[f->total_tracks - 1]->decoderConfig = malloc(f->track[f->total_tracks - 1]->decoderConfigLen);
355 if (f->track[f->total_tracks - 1]->decoderConfig)
356 {
357 mp4ff_read_data(f, f->track[f->total_tracks - 1]->decoderConfig, f->track[f->total_tracks - 1]->decoderConfigLen);
358 } else {
359 f->track[f->total_tracks - 1]->decoderConfigLen = 0;
360 }
361
362 /* will skip the remainder of the atom */
363 return 0;
364 }
365
mp4ff_read_mp4a(mp4ff_t * f)366 static int32_t mp4ff_read_mp4a(mp4ff_t *f)
367 {
368 uint64_t size;
369 int32_t i;
370 uint8_t atom_type = 0;
371 uint8_t header_size = 0;
372
373 for (i = 0; i < 6; i++)
374 {
375 mp4ff_read_char(f); /* reserved */
376 }
377 /* data_reference_index */ mp4ff_read_int16(f);
378
379 mp4ff_read_int32(f); /* reserved */
380 mp4ff_read_int32(f); /* reserved */
381
382 f->track[f->total_tracks - 1]->channelCount = mp4ff_read_int16(f);
383 f->track[f->total_tracks - 1]->sampleSize = mp4ff_read_int16(f);
384
385 mp4ff_read_int16(f);
386 mp4ff_read_int16(f);
387
388 f->track[f->total_tracks - 1]->sampleRate = mp4ff_read_int16(f);
389
390 mp4ff_read_int16(f);
391
392 size = mp4ff_atom_read_header(f, &atom_type, &header_size);
393 if (atom_type == ATOM_ESDS)
394 {
395 mp4ff_read_esds(f);
396 }
397
398 return 0;
399 }
400
mp4ff_read_stsd(mp4ff_t * f)401 static int32_t mp4ff_read_stsd(mp4ff_t *f)
402 {
403 int32_t i;
404 uint8_t header_size = 0;
405
406 mp4ff_read_char(f); /* version */
407 mp4ff_read_int24(f); /* flags */
408
409 f->track[f->total_tracks - 1]->stsd_entry_count = mp4ff_read_int32(f);
410
411 for (i = 0; i < f->track[f->total_tracks - 1]->stsd_entry_count; i++)
412 {
413 uint64_t skip = mp4ff_position(f);
414 uint64_t size;
415 uint8_t atom_type = 0;
416 size = mp4ff_atom_read_header(f, &atom_type, &header_size);
417 skip += size;
418
419 if (atom_type == ATOM_MP4A)
420 {
421 f->track[f->total_tracks - 1]->type = TRACK_AUDIO;
422 mp4ff_read_mp4a(f);
423 } else if (atom_type == ATOM_MP4V) {
424 f->track[f->total_tracks - 1]->type = TRACK_VIDEO;
425 } else if (atom_type == ATOM_MP4S) {
426 f->track[f->total_tracks - 1]->type = TRACK_SYSTEM;
427 } else if (atom_type == ATOM_TEXT) {
428 f->track[f->total_tracks - 1]->type = TRACK_TEXT;
429 } else {
430 f->track[f->total_tracks - 1]->type = TRACK_UNKNOWN;
431 }
432
433 mp4ff_set_position(f, skip);
434 }
435
436 return 0;
437 }
438
mp4ff_read_stsc(mp4ff_t * f)439 static int32_t mp4ff_read_stsc(mp4ff_t *f)
440 {
441 trace ("mp4ff_read_stsc\n");
442 int32_t i;
443
444 mp4ff_read_char(f); /* version */
445 mp4ff_read_int24(f); /* flags */
446 f->track[f->total_tracks - 1]->stsc_entry_count = mp4ff_read_int32(f);
447
448 f->track[f->total_tracks - 1]->stsc_first_chunk =
449 (int32_t*)malloc(f->track[f->total_tracks - 1]->stsc_entry_count*sizeof(int32_t));
450 f->track[f->total_tracks - 1]->stsc_samples_per_chunk =
451 (int32_t*)malloc(f->track[f->total_tracks - 1]->stsc_entry_count*sizeof(int32_t));
452 f->track[f->total_tracks - 1]->stsc_sample_desc_index =
453 (int32_t*)malloc(f->track[f->total_tracks - 1]->stsc_entry_count*sizeof(int32_t));
454
455 for (i = 0; i < f->track[f->total_tracks - 1]->stsc_entry_count; i++)
456 {
457 f->track[f->total_tracks - 1]->stsc_first_chunk[i] = mp4ff_read_int32(f);
458 f->track[f->total_tracks - 1]->stsc_samples_per_chunk[i] = mp4ff_read_int32(f);
459 f->track[f->total_tracks - 1]->stsc_sample_desc_index[i] = mp4ff_read_int32(f);
460 }
461
462 return 0;
463 }
464
mp4ff_read_stco(mp4ff_t * f)465 static int32_t mp4ff_read_stco(mp4ff_t *f)
466 {
467 int32_t i;
468
469 mp4ff_read_char(f); /* version */
470 mp4ff_read_int24(f); /* flags */
471 f->track[f->total_tracks - 1]->stco_entry_count = mp4ff_read_int32(f);
472
473 f->track[f->total_tracks - 1]->stco_chunk_offset =
474 (int32_t*)malloc(f->track[f->total_tracks - 1]->stco_entry_count*sizeof(int32_t));
475
476 for (i = 0; i < f->track[f->total_tracks - 1]->stco_entry_count; i++)
477 {
478 f->track[f->total_tracks - 1]->stco_chunk_offset[i] = mp4ff_read_int32(f);
479 }
480
481 return 0;
482 }
483
mp4ff_read_ctts(mp4ff_t * f)484 static int32_t mp4ff_read_ctts(mp4ff_t *f)
485 {
486 int32_t i;
487 mp4ff_track_t * p_track = f->track[f->total_tracks - 1];
488
489 if (p_track->ctts_entry_count) return 0;
490
491 mp4ff_read_char(f); /* version */
492 mp4ff_read_int24(f); /* flags */
493 p_track->ctts_entry_count = mp4ff_read_int32(f);
494
495 p_track->ctts_sample_count = (int32_t*)malloc(p_track->ctts_entry_count * sizeof(int32_t));
496 p_track->ctts_sample_offset = (int32_t*)malloc(p_track->ctts_entry_count * sizeof(int32_t));
497
498 if (p_track->ctts_sample_count == 0 || p_track->ctts_sample_offset == 0)
499 {
500 if (p_track->ctts_sample_count) {free(p_track->ctts_sample_count);p_track->ctts_sample_count=0;}
501 if (p_track->ctts_sample_offset) {free(p_track->ctts_sample_offset);p_track->ctts_sample_offset=0;}
502 p_track->ctts_entry_count = 0;
503 return 0;
504 }
505 else
506 {
507 for (i = 0; i < f->track[f->total_tracks - 1]->ctts_entry_count; i++)
508 {
509 p_track->ctts_sample_count[i] = mp4ff_read_int32(f);
510 p_track->ctts_sample_offset[i] = mp4ff_read_int32(f);
511 }
512 return 1;
513 }
514 }
515
mp4ff_read_stts(mp4ff_t * f)516 static int32_t mp4ff_read_stts(mp4ff_t *f)
517 {
518 trace ("mp4ff_read_stts\n");
519 int32_t i;
520 mp4ff_track_t * p_track = f->track[f->total_tracks - 1];
521
522 if (p_track->stts_entry_count) return 0;
523
524 mp4ff_read_char(f); /* version */
525 mp4ff_read_int24(f); /* flags */
526 p_track->stts_entry_count = mp4ff_read_int32(f);
527
528 p_track->stts_sample_count = (int32_t*)malloc(p_track->stts_entry_count * sizeof(int32_t));
529 p_track->stts_sample_delta = (int32_t*)malloc(p_track->stts_entry_count * sizeof(int32_t));
530
531 if (p_track->stts_sample_count == 0 || p_track->stts_sample_delta == 0)
532 {
533 if (p_track->stts_sample_count) {free(p_track->stts_sample_count);p_track->stts_sample_count=0;}
534 if (p_track->stts_sample_delta) {free(p_track->stts_sample_delta);p_track->stts_sample_delta=0;}
535 p_track->stts_entry_count = 0;
536 return 0;
537 }
538 else
539 {
540 for (i = 0; i < f->track[f->total_tracks - 1]->stts_entry_count; i++)
541 {
542 p_track->stts_sample_count[i] = mp4ff_read_int32(f);
543 p_track->stts_sample_delta[i] = mp4ff_read_int32(f);
544 }
545 return 1;
546 }
547 }
548
mp4ff_read_mvhd(mp4ff_t * f)549 static int32_t mp4ff_read_mvhd(mp4ff_t *f)
550 {
551 int32_t i;
552
553 mp4ff_read_char(f); /* version */
554 mp4ff_read_int24(f); /* flags */
555 /* creation_time */ mp4ff_read_int32(f);
556 /* modification_time */ mp4ff_read_int32(f);
557 f->time_scale = mp4ff_read_int32(f);
558 f->duration = mp4ff_read_int32(f);
559 /* preferred_rate */ mp4ff_read_int32(f); /*mp4ff_read_fixed32(f);*/
560 /* preferred_volume */ mp4ff_read_int16(f); /*mp4ff_read_fixed16(f);*/
561 for (i = 0; i < 10; i++)
562 {
563 /* reserved */ mp4ff_read_char(f);
564 }
565 for (i = 0; i < 9; i++)
566 {
567 mp4ff_read_int32(f); /* matrix */
568 }
569 /* preview_time */ mp4ff_read_int32(f);
570 /* preview_duration */ mp4ff_read_int32(f);
571 /* poster_time */ mp4ff_read_int32(f);
572 /* selection_time */ mp4ff_read_int32(f);
573 /* selection_duration */ mp4ff_read_int32(f);
574 /* current_time */ mp4ff_read_int32(f);
575 /* next_track_id */ mp4ff_read_int32(f);
576
577 return 0;
578 }
579
mp4ff_read_tkhd(mp4ff_t * f)580 static int32_t mp4ff_read_tkhd(mp4ff_t *f)
581 {
582 uint8_t version;
583 uint32_t flags;
584 version = mp4ff_read_char(f); /* version */
585 flags = mp4ff_read_int24(f); /* flags */
586 if (version==1)
587 {
588 mp4ff_read_int64(f);//creation-time
589 mp4ff_read_int64(f);//modification-time
590 f->track[f->total_tracks - 1]->id = mp4ff_read_int32(f);//track-id
591 mp4ff_read_int32(f);//reserved
592 // f->track[f->total_tracks - 1]->duration = mp4ff_read_int64(f);//duration
593 }
594 else //version == 0
595 {
596 mp4ff_read_int32(f);//creation-time
597 mp4ff_read_int32(f);//modification-time
598 f->track[f->total_tracks - 1]->id = mp4ff_read_int32(f);//track-id
599 mp4ff_read_int32(f);//reserved
600 // f->track[f->total_tracks - 1]->duration = mp4ff_read_int32(f);//duration
601 // if (f->track[f->total_tracks - 1]->duration == 0xFFFFFFFF)
602 // f->track[f->total_tracks - 1]->duration = 0xFFFFFFFFFFFFFFFF;
603
604 }
605 #if 0
606 mp4ff_read_int32(f);//reserved
607 mp4ff_read_int32(f);//reserved
608 mp4ff_read_int16(f);//layer
609 mp4ff_read_int16(f);//pre-defined
610 mp4ff_read_int16(f);//volume
611 mp4ff_read_int16(f);//reserved
612
613 //matrix
614 mp4ff_read_int32(f); mp4ff_read_int32(f); mp4ff_read_int32(f);
615 mp4ff_read_int32(f); mp4ff_read_int32(f); mp4ff_read_int32(f);
616 mp4ff_read_int32(f); mp4ff_read_int32(f); mp4ff_read_int32(f);
617 mp4ff_read_int32(f);//width
618 mp4ff_read_int32(f);//height
619 #endif
620 return 1;
621 }
622
mp4ff_read_mdhd(mp4ff_t * f)623 static int32_t mp4ff_read_mdhd(mp4ff_t *f)
624 {
625 uint32_t version;
626
627 version = mp4ff_read_int32(f);
628 if (version==1)
629 {
630 mp4ff_read_int64(f);//creation-time
631 mp4ff_read_int64(f);//modification-time
632 f->track[f->total_tracks - 1]->timeScale = mp4ff_read_int32(f);//timescale
633 f->track[f->total_tracks - 1]->duration = mp4ff_read_int64(f);//duration
634 }
635 else //version == 0
636 {
637 uint32_t temp;
638
639 mp4ff_read_int32(f);//creation-time
640 mp4ff_read_int32(f);//modification-time
641 f->track[f->total_tracks - 1]->timeScale = mp4ff_read_int32(f);//timescale
642 temp = mp4ff_read_int32(f);
643 f->track[f->total_tracks - 1]->duration = (temp == (uint32_t)(-1)) ? (uint64_t)(-1) : (uint64_t)(temp);
644 }
645 mp4ff_read_int16(f);
646 mp4ff_read_int16(f);
647 return 1;
648 }
649 #ifdef USE_TAGGING
mp4ff_read_meta(mp4ff_t * f,const uint64_t size)650 static int32_t mp4ff_read_meta(mp4ff_t *f, const uint64_t size)
651 {
652 uint64_t subsize, sumsize = 0;
653 uint8_t atom_type;
654 uint8_t header_size = 0;
655
656 mp4ff_read_char(f); /* version */
657 mp4ff_read_int24(f); /* flags */
658
659 while (sumsize < (size-(header_size+4)))
660 {
661 subsize = mp4ff_atom_read_header(f, &atom_type, &header_size);
662 if (subsize <= header_size+4)
663 return 1;
664 if (atom_type == ATOM_ILST)
665 {
666 mp4ff_parse_metadata(f, (uint32_t)(subsize-(header_size+4)));
667 } else {
668 mp4ff_set_position(f, mp4ff_position(f)+subsize-header_size);
669 }
670 sumsize += subsize;
671 }
672
673 return 0;
674 }
675 #endif
676
mp4ff_read_chpl(mp4ff_t * f,const uint64_t size)677 static int32_t mp4ff_read_chpl(mp4ff_t *f, const uint64_t size)
678 {
679 int i;
680 int i_read = size;
681
682 mp4ff_read_char(f); /* version */
683 mp4ff_read_int24(f); /* flags */
684
685 mp4ff_chapterdata_t *p_chpl = &f->chapters;
686
687 p_chpl->i_chapter = mp4ff_read_char (f);
688 i_read -= 5;
689
690 for( i = 0; i < p_chpl->i_chapter; i++ )
691 {
692 uint64_t i_start;
693 uint8_t i_len;
694 int i_copy;
695 i_start = mp4ff_read_int64 (f);
696 i_read -= 8;
697 i_len = mp4ff_read_char (f);
698 i_read -= 1;
699
700 p_chpl->chapter[i].psz_name = malloc( i_len + 1 );
701 if( !p_chpl->chapter[i].psz_name )
702 goto error;
703
704 i_copy = i_len < i_read ? i_len : i_read;
705 if( i_copy > 0 )
706 mp4ff_read_data (f, p_chpl->chapter[i].psz_name, i_copy);
707 p_chpl->chapter[i].psz_name[i_copy] = '\0';
708 p_chpl->chapter[i].i_start = i_start;
709
710 i_read -= i_copy;
711 }
712 /* Bubble sort by increasing start date */
713 do
714 {
715 for( i = 0; i < p_chpl->i_chapter - 1; i++ )
716 {
717 if( p_chpl->chapter[i].i_start > p_chpl->chapter[i+1].i_start )
718 {
719 char *psz = p_chpl->chapter[i+1].psz_name;
720 int64_t i64 = p_chpl->chapter[i+1].i_start;
721
722 p_chpl->chapter[i+1].psz_name = p_chpl->chapter[i].psz_name;
723 p_chpl->chapter[i+1].i_start = p_chpl->chapter[i].i_start;
724
725 p_chpl->chapter[i].psz_name = psz;
726 p_chpl->chapter[i].i_start = i64;
727
728 i = -1;
729 break;
730 }
731 }
732 } while( i == -1 );
733
734 return 0;
735
736 error:
737 return -1;
738 }
739
mp4ff_chapters_get_num_items(mp4ff_t * f)740 int32_t mp4ff_chapters_get_num_items (mp4ff_t *f)
741 {
742 return f->chapters.i_chapter;
743 }
744
mp4ff_chapters_get_item(mp4ff_t * f,int i)745 const char *mp4ff_chapters_get_item (mp4ff_t *f, int i)
746 {
747 return f->chapters.chapter[i].psz_name;
748 }
749
mp4ff_chapters_free(mp4ff_t * f)750 void mp4ff_chapters_free (mp4ff_t *f)
751 {
752 int i;
753 for (i = 0; i < f->chapters.i_chapter; i++)
754 {
755 free (f->chapters.chapter[i].psz_name);
756 f->chapters.chapter[i].psz_name = NULL;
757 }
758 }
759
mp4ff_read_tref(mp4ff_t * f,const uint64_t size)760 static int32_t mp4ff_read_tref(mp4ff_t *f, const uint64_t size)
761 {
762 int i;
763
764 mp4ff_trefdata_t *p_tref = &f->tref;
765
766 p_tref->i_track_ID = NULL;
767 p_tref->i_entry_count = (size-8)/ sizeof(uint32_t);
768 if( p_tref->i_entry_count > 0 ) {
769 p_tref->i_track_ID = calloc( p_tref->i_entry_count, sizeof(uint32_t) );
770 }
771 if( p_tref->i_track_ID == NULL )
772 return -1;
773
774 for( i = 0; i < p_tref->i_entry_count; i++ )
775 {
776 p_tref->i_track_ID[i] = mp4ff_read_int32 (f);
777 }
778
779 return 0;
780 }
781
mp4ff_tref_free(mp4ff_t * f)782 void mp4ff_tref_free (mp4ff_t *f)
783 {
784 if (f->tref.i_track_ID) {
785 free (f->tref.i_track_ID);
786 f->tref.i_track_ID = NULL;
787 }
788 }
789
mp4ff_chap_get_num_tracks(mp4ff_t * f)790 int32_t mp4ff_chap_get_num_tracks (mp4ff_t *f)
791 {
792 return f->tref.i_entry_count;
793 }
794
mp4ff_chap_get_track_id(mp4ff_t * f,int t)795 int32_t mp4ff_chap_get_track_id (mp4ff_t *f, int t)
796 {
797 return f->tref.i_track_ID[t];
798 }
799
mp4ff_atom_read(mp4ff_t * f,const int32_t size,const uint8_t atom_type)800 int32_t mp4ff_atom_read(mp4ff_t *f, const int32_t size, const uint8_t atom_type)
801 {
802 uint64_t dest_position = mp4ff_position(f)+size-8;
803 if (atom_type == ATOM_STSZ)
804 {
805 /* sample size box */
806 mp4ff_read_stsz(f);
807 } else if (atom_type == ATOM_STTS) {
808 /* time to sample box */
809 mp4ff_read_stts(f);
810 } else if (atom_type == ATOM_CTTS) {
811 /* composition offset box */
812 mp4ff_read_ctts(f);
813 } else if (atom_type == ATOM_STSC) {
814 /* sample to chunk box */
815 mp4ff_read_stsc(f);
816 } else if (atom_type == ATOM_STCO) {
817 /* chunk offset box */
818 mp4ff_read_stco(f);
819 } else if (atom_type == ATOM_STSD) {
820 /* sample description box */
821 mp4ff_read_stsd(f);
822 } else if (atom_type == ATOM_MVHD) {
823 /* movie header box */
824 mp4ff_read_mvhd(f);
825 } else if (atom_type == ATOM_MDHD) {
826 /* track header */
827 mp4ff_read_mdhd(f);
828 #ifdef USE_TAGGING
829 } else if (atom_type == ATOM_META) {
830 /* iTunes Metadata box */
831 mp4ff_read_meta(f, size);
832 #endif
833 } else if (atom_type == ATOM_CHPL) {
834 mp4ff_read_chpl(f, size);
835 } else if (atom_type == ATOM_CHAP) {
836 mp4ff_read_tref(f, size);
837 } else if (atom_type == ATOM_TKHD) {
838 mp4ff_read_tkhd(f);
839 }
840
841 mp4ff_set_position(f, dest_position);
842
843
844 return 0;
845 }
846
847 #if 0
848 int mp4ff_track_create_chunks_index(mp4ff_t *f, mp4ff_track_t *trk)
849 {
850 unsigned int i_chunk;
851 unsigned int i_index, i_last;
852
853 // handle case when ( (!stco && !co64) || !stsc )
854 // NOTE: stco and co64 have the same data
855
856 if (!trk->stco_entry_count || !trk->stsc_entry_count)
857 {
858 trace ("no chunks\n");
859 return -1;
860 }
861
862 trk->i_chunk_count = trk->stco_entry_count;
863
864 trace ("\033[0;31mchunk count %d\033[37;0m\n", trk->i_chunk_count);
865 trk->chunk_sample_first = malloc (sizeof (int32_t) * trk->i_chunk_count);
866 trk->chunk_first_dts = malloc (sizeof (int32_t) * trk->i_chunk_count);
867 trk->chunk_last_dts = malloc (sizeof (int32_t) * trk->i_chunk_count);
868 trk->p_sample_count_dts = malloc (sizeof (int32_t *) * trk->i_chunk_count);
869 trk->p_sample_delta_dts = malloc (sizeof (int32_t *) * trk->i_chunk_count);
870 trk->p_sample_count_pts = malloc (sizeof (int32_t *) * trk->i_chunk_count);
871 trk->p_sample_offset_pts = malloc (sizeof (int32_t *) * trk->i_chunk_count);
872
873 /* first we read chunk offset */
874 for( i_chunk = 0; i_chunk < trk->i_chunk_count; i_chunk++ )
875 {
876 // chunk.i_offset = stco_chunk_offset[i_chunk]
877 trk->chunk_first_dts[i_chunk] = 0;
878 trk->p_sample_count_dts[i_chunk] = NULL;
879 trk->p_sample_delta_dts[i_chunk] = NULL;
880 trk->p_sample_count_pts[i_chunk] = NULL;
881 trk->p_sample_offset_pts[i_chunk] = NULL;
882 }
883
884 /* now we read index for SampleEntry( soun vide mp4a mp4v ...)
885 to be used for the sample XXX begin to 1
886 We construct it begining at the end */
887 i_last = trk->i_chunk_count; /* last chunk proceded */
888 i_index = trk->stsc_entry_count;
889 if( !i_index )
890 {
891 trace ("cannot read chunk table or table empty\n");
892 return -1;
893 }
894 trk->chunk_sample_first[0] = 0;
895 trace ("\033[0;35mchunk_sample_first[%d]=%d\033[37;0m\n", 0, trk->chunk_sample_first[0]);
896 for (int i = 1; i < trk->i_chunk_count; i++)
897 {
898 trk->chunk_sample_first[i] =
899 trk->chunk_sample_first[i-1] +
900 trk->stsc_samples_per_chunk[i-1];
901 trace ("\033[0;35mchunk_sample_first[%d]=%d\033[37;0m\n", i, trk->chunk_sample_first[i]);
902 }
903
904 trace ("track[Id 0x%x] read %d chunks\n", trk->id, trk->i_chunk_count);
905 return 0;
906 }
907
908 int mp4ff_track_create_samples_index (mp4ff_t *f, mp4ff_track_t *trk)
909 {
910 /* TODO use also stss and stsh table for seeking */
911 /* FIXME use edit table */
912 int64_t i_sample;
913 int64_t i_chunk;
914
915 int64_t i_index;
916 int64_t i_index_sample_used;
917
918 int64_t i_next_dts;
919
920 if (trk->stsz_sample_count == 0) {
921 trace ("stsz not found\n");
922 return -1;
923 }
924 if (trk->stts_entry_count == 0) {
925 trace ("stts not found\n");
926 return -1;
927 }
928
929 // we already have the table, don't construct anything
930 // sample_size = stsz_sample_size == 0 ? stsz_table[i_sample] : stsz_sample_size
931
932 /* Use stts table to create a sample number -> dts table.
933 * XXX: if we don't want to waste too much memory, we can't expand
934 * the box! so each chunk will contain an "extract" of this table
935 * for fast research (problem with raw stream where a sample is sometime
936 * just channels*bits_per_sample/8 */
937
938 i_next_dts = 0;
939 i_index = 0; i_index_sample_used = 0;
940 for( i_chunk = 0; i_chunk < trk->i_chunk_count; i_chunk++ )
941 {
942 trace ("calculating first/last dts for chunk %d\n", i_chunk);
943 int64_t i_entry, i_sample_count, i;
944
945 /* save first dts */
946 trk->chunk_first_dts[i_chunk] = i_next_dts;
947 trk->chunk_last_dts[i_chunk] = i_next_dts;
948 trace ("init %lld\n", i_next_dts);
949
950 /* count how many entries are needed for this chunk
951 * for p_sample_delta_dts and p_sample_count_dts */
952 i_sample_count = trk->stsc_samples_per_chunk[i_chunk];
953 trace ("init i_sample_count %d\n", i_sample_count);
954
955 i_entry = 0;
956 while( i_sample_count > 0 )
957 {
958 i_sample_count -= trk->stts_sample_count[i_index+i_entry];
959 trace ("- i_sample_count %d\n", i_sample_count);
960 /* don't count already used sample in this entry */
961 if( i_entry == 0 ) {
962 i_sample_count += i_index_sample_used;
963 trace ("+ i_sample_count %d\n", i_sample_count);
964 }
965
966 i_entry++;
967 }
968 trace ("+ i_entry %d\n", i_entry);
969 /* allocate them */
970 trace ("alloc mem for chunk %d (%d entries, %d samples-per-chunk)\n", i_chunk, i_entry, trk->stsc_samples_per_chunk[i_chunk]);
971 trk->p_sample_count_dts[i_chunk] = calloc( i_entry, sizeof( uint32_t ) );
972 trk->p_sample_delta_dts[i_chunk] = calloc( i_entry, sizeof( uint32_t ) );
973
974 if( !trk->p_sample_count_dts[i_chunk] || !trk->p_sample_delta_dts[i_chunk] ) {
975 trace ("out of memory allocating p_sample_count_dts or p_sample_delta_dts\n");
976 return -1; // oom
977 }
978
979 /* now copy */
980 i_sample_count = trk->stsc_samples_per_chunk[i_chunk];
981 for( i = 0; i < i_entry; i++ )
982 {
983 int64_t i_used;
984 int64_t i_rest;
985
986 i_rest = trk->stts_sample_count[i_index] - i_index_sample_used;
987
988 i_used = min( i_rest, i_sample_count );
989
990 i_index_sample_used += i_used;
991 i_sample_count -= i_used;
992 i_next_dts += i_used * trk->stts_sample_delta[i_index];
993
994 trk->p_sample_count_dts[i_chunk][i] = i_used;
995 trk->p_sample_delta_dts[i_chunk][i] = trk->stts_sample_delta[i_index];
996 if( i_used > 0 )
997 trk->chunk_last_dts[i_chunk] = i_next_dts - trk->p_sample_delta_dts[i_chunk][i];
998
999 if( i_index_sample_used >= trk->stts_sample_count[i_index] )
1000 {
1001 i_index++;
1002 i_index_sample_used = 0;
1003 }
1004 }
1005 }
1006
1007 /* Find ctts
1008 * Gives the delta between decoding time (dts) and composition table (pts)
1009 */
1010 if (trk->ctts_entry_count)
1011 {
1012 /* Create pts-dts table per chunk */
1013 i_index = 0; i_index_sample_used = 0;
1014 for( i_chunk = 0; i_chunk < trk->i_chunk_count; i_chunk++ )
1015 {
1016 int64_t i_entry, i_sample_count, i;
1017
1018 /* count how many entries are needed for this chunk
1019 * for p_sample_delta_dts and p_sample_count_dts */
1020 i_sample_count = trk->stsc_samples_per_chunk[i_chunk];
1021
1022 i_entry = 0;
1023 while( i_sample_count > 0 )
1024 {
1025 i_sample_count -= trk->ctts_sample_count[i_index+i_entry];
1026
1027 /* don't count already used sample in this entry */
1028 if( i_entry == 0 )
1029 i_sample_count += i_index_sample_used;
1030
1031 i_entry++;
1032 }
1033 if (i_entry == 0) {
1034 continue;
1035 }
1036
1037 /* allocate them */
1038 trk->p_sample_count_pts[i_chunk] = calloc( i_entry, sizeof( uint32_t ) );
1039 trk->p_sample_offset_pts[i_chunk] = calloc( i_entry, sizeof( int32_t ) );
1040 if( !trk->p_sample_count_pts[i_chunk] || !trk->p_sample_offset_pts[i_chunk] ) {
1041 trace ("out of memory allocating p_sample_count_pts or p_sample_offset_pts\n");
1042 return -1; // oom
1043 }
1044
1045 /* now copy */
1046 i_sample_count = trk->stsc_samples_per_chunk[i_chunk];
1047 for( i = 0; i < i_entry; i++ )
1048 {
1049 int64_t i_used;
1050 int64_t i_rest;
1051
1052 i_rest = trk->ctts_sample_count[i_index] -
1053 i_index_sample_used;
1054
1055 i_used = min( i_rest, i_sample_count );
1056
1057 i_index_sample_used += i_used;
1058 i_sample_count -= i_used;
1059
1060 trk->p_sample_count_pts[i_chunk][i] = i_used;
1061 trk->p_sample_offset_pts[i_chunk][i] = trk->ctts_sample_offset[i_index];
1062
1063 if( i_index_sample_used >= trk->ctts_sample_count[i_index] )
1064 {
1065 i_index++;
1066 i_index_sample_used = 0;
1067 }
1068 }
1069 }
1070 }
1071
1072 trace ("track[Id 0x%x] read %d samples length:%llds\n",
1073 trk->id, trk->stsz_sample_count,
1074 i_next_dts / trk->timeScale );
1075
1076 return 0;
1077 }
1078
1079 int64_t mp4ff_get_track_dts (mp4ff_t *f, int t, int s)
1080 {
1081 mp4ff_track_t *p_track = f->track[t];
1082 // find chunk for the sample
1083 int i_chunk = 0;
1084 for (i_chunk = 0; i_chunk < p_track->i_chunk_count-1; i_chunk++) {
1085 if (p_track->chunk_sample_first[i_chunk+1] > s) {
1086 break;
1087 }
1088 }
1089 // trace ("i_chunk for sample %d: %d (out of %d)\n", s, i_chunk, p_track->i_chunk_count);
1090
1091 unsigned int i_index = 0;
1092 unsigned int i_sample = s - p_track->chunk_sample_first[i_chunk];
1093 int64_t i_dts = p_track->chunk_first_dts[i_chunk];
1094 trace ("start dts: %lld (i_sample: %d)\n", i_dts, i_sample);
1095
1096 while( i_sample > 0 )
1097 {
1098 if( i_sample > p_track->p_sample_count_dts[i_chunk][i_index] )
1099 {
1100 i_dts += p_track->p_sample_count_dts[i_chunk][i_index] *
1101 p_track->p_sample_delta_dts[i_chunk][i_index];
1102 i_sample -= p_track->p_sample_count_dts[i_chunk][i_index];
1103 i_index++;
1104 }
1105 else
1106 {
1107 i_dts += i_sample * p_track->p_sample_delta_dts[i_chunk][i_index];
1108 break;
1109 }
1110 }
1111
1112
1113 #if 0
1114 // we don't need elst
1115 /* now handle elst */
1116 if (p_track->elst_entry_count)
1117 {
1118 /* convert to offset */
1119 if( ( p_track->elst_media_rate_integer[p_track->i_elst] > 0 ||
1120 p_track->elst_media_rate_fraction[p_track->i_elst] > 0 ) &&
1121 p_track->elst_media_time[p_track->i_elst] > 0 )
1122 {
1123 i_dts -= p_track->elst_media_time[p_track->i_elst];
1124 }
1125
1126 /* add i_elst_time */
1127 i_dts += p_track->i_elst_time * p_track->timeScale /
1128 f->time_scale;
1129
1130 if( i_dts < 0 ) i_dts = 0;
1131 }
1132 #endif
1133
1134 return (int64_t)1000000 * i_dts / p_track->timeScale;
1135 }
1136
1137 int64_t mp4ff_get_track_pts_delta(mp4ff_t *f, int t, int i_sample)
1138 {
1139 mp4ff_track_t *p_track = f->track[t];
1140 // find chunk for the sample
1141 int i_chunk = 0;
1142 for (i_chunk = 0; i_chunk < p_track->i_chunk_count-1; i_chunk++) {
1143 if (p_track->chunk_sample_first[i_chunk+1] > i_sample) {
1144 break;
1145 }
1146 }
1147 // trace ("i_chunk for sample %d: %d (out of %d)\n", i_sample, i_chunk, p_track->i_chunk_count);
1148 unsigned int i_index = 0;
1149 i_sample = i_sample - p_track->chunk_sample_first[i_chunk];
1150
1151 if( p_track->p_sample_count_pts[i_chunk] == NULL || p_track->p_sample_offset_pts[i_chunk] == NULL ) {
1152 trace ("pts info not found :(\n");
1153 return -1;
1154 }
1155
1156 for( i_index = 0;; i_index++ )
1157 {
1158 if( i_sample < p_track->p_sample_count_pts[i_chunk][i_index] )
1159 return p_track->p_sample_offset_pts[i_chunk][i_index] * (int64_t)1000000 /
1160 (int64_t)p_track->timeScale;
1161
1162 i_sample -= p_track->p_sample_count_pts[i_chunk][i_index];
1163 }
1164 return 0;
1165 }
1166
1167 int mp4ff_get_track_sample_size(mp4ff_t *f, int t, int s)
1168 {
1169 mp4ff_track_t *p_track = f->track[t];
1170 int i_size;
1171
1172 if( p_track->stsz_sample_size == 0 )
1173 {
1174 /* most simple case */
1175 return p_track->stsz_table[s];
1176 }
1177 if(p_track->type != TRACK_AUDIO)
1178 {
1179 return p_track->stsz_sample_size;
1180 }
1181
1182 // that's all we need for chapters, sound length is calculated differently for now
1183 return 0;
1184 #if 0
1185 p_soun = p_track->p_sample->data.p_sample_soun;
1186
1187 if( p_soun->i_qt_version == 1 )
1188 {
1189 int i_samples = p_track->chunk[p_track->i_chunk].i_sample_count;
1190 if( p_track->fmt.audio.i_blockalign > 1 )
1191 i_samples = p_soun->i_sample_per_packet;
1192
1193 i_size = i_samples / p_soun->i_sample_per_packet * p_soun->i_bytes_per_frame;
1194 }
1195 else if( p_track->i_sample_size > 256 )
1196 {
1197 /* We do that so we don't read too much data
1198 * (in this case we are likely dealing with compressed data) */
1199 i_size = p_track->i_sample_size;
1200 }
1201 else
1202 {
1203 /* Read a bunch of samples at once */
1204 int i_samples = p_track->chunk[p_track->i_chunk].i_sample_count -
1205 ( p_track->i_sample -
1206 p_track->chunk[p_track->i_chunk].i_sample_first );
1207
1208 i_samples = __MIN( QT_V0_MAX_SAMPLES, i_samples );
1209 i_size = i_samples * p_track->i_sample_size;
1210 }
1211
1212 //fprintf( stderr, "size=%d\n", i_size );
1213 return i_size;
1214 #endif
1215 }
1216 #endif
1217