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