]> git.sesse.net Git - vlc/blob - modules/demux/mp4/mp4.c
demux: mp4: update PCR on seek
[vlc] / modules / demux / mp4 / mp4.c
1 /*****************************************************************************
2  * mp4.c : MP4 file input module for vlc
3  *****************************************************************************
4  * Copyright (C) 2001-2004, 2010 VLC authors and VideoLAN
5  *
6  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
7  *
8  * This program is free software; you can redistribute it and/or modify it
9  * under the terms of the GNU Lesser General Public License as published by
10  * the Free Software Foundation; either version 2.1 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public License
19  * along with this program; if not, write to the Free Software Foundation,
20  * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
21  *****************************************************************************/
22
23 /*****************************************************************************
24  * Preamble
25  *****************************************************************************/
26
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
30
31 #include <vlc_common.h>
32 #include <vlc_plugin.h>
33
34 #include <vlc_demux.h>
35 #include <vlc_charset.h>                           /* EnsureUTF8 */
36 #include <vlc_meta.h>                              /* vlc_meta_t, vlc_meta_ */
37 #include <vlc_input.h>
38 #include <assert.h>
39
40 #include "libmp4.h"
41 #include "id3genres.h"                             /* for ATOM_gnre */
42
43 /*****************************************************************************
44  * Module descriptor
45  *****************************************************************************/
46 static int  Open ( vlc_object_t * );
47 static void Close( vlc_object_t * );
48
49 vlc_module_begin ()
50     set_category( CAT_INPUT )
51     set_subcategory( SUBCAT_INPUT_DEMUX )
52     set_description( N_("MP4 stream demuxer") )
53     set_shortname( N_("MP4") )
54     set_capability( "demux", 240 )
55     set_callbacks( Open, Close )
56 vlc_module_end ()
57
58 /*****************************************************************************
59  * Local prototypes
60  *****************************************************************************/
61 static int   Demux   ( demux_t * );
62 static int   DemuxRef( demux_t *p_demux ){ (void)p_demux; return 0;}
63 static int   DemuxFrg( demux_t * );
64 static int   DemuxAsLeaf( demux_t * );
65 static int   Seek    ( demux_t *, mtime_t );
66 static int   Control ( demux_t *, int, va_list );
67
68 typedef struct mp4_fragment_t mp4_fragment_t;
69 struct mp4_fragment_t
70 {
71     uint64_t i_chunk_range_min_offset;
72     uint64_t i_chunk_range_max_offset;
73     uint64_t i_duration;
74     MP4_Box_t *p_moox;
75     mp4_fragment_t *p_next;
76 };
77
78 struct demux_sys_t
79 {
80     MP4_Box_t    *p_root;      /* container for the whole file */
81
82     mtime_t      i_pcr;
83
84     uint64_t     i_overall_duration; /* Full duration, including all fragments */
85     uint64_t     i_time;         /* time position of the presentation
86                                   * in movie timescale */
87     uint32_t     i_timescale;    /* movie time scale */
88     uint64_t     i_duration;     /* movie duration */
89     unsigned int i_tracks;       /* number of tracks */
90     mp4_track_t  *track;         /* array of track */
91     float        f_fps;          /* number of frame per seconds */
92
93     bool         b_fragmented;   /* fMP4 */
94     bool         b_seekable;
95     bool         b_fastseekable;
96     bool         b_smooth;       /* Is it Smooth Streaming? */
97
98     bool            b_index_probed;
99     bool            b_fragments_probed;
100     mp4_fragment_t  moovfragment; /* moov */
101     mp4_fragment_t *p_fragments;  /* known fragments (moof following moov) */
102
103     struct
104     {
105         mp4_fragment_t *p_fragment;
106         uint32_t        i_current_box_type;
107         uint32_t        i_mdatbytesleft;
108     } context;
109
110     /* */
111     MP4_Box_t    *p_tref_chap;
112
113     /* */
114     input_title_t *p_title;
115 };
116
117 #define BOXDATA(type) type->data.type
118
119 /*****************************************************************************
120  * Declaration of local function
121  *****************************************************************************/
122 static void MP4_TrackCreate ( demux_t *, mp4_track_t *, MP4_Box_t  *, bool b_force_enable );
123 static int MP4_frg_TrackCreate( demux_t *, mp4_track_t *, MP4_Box_t *);
124 static void MP4_TrackDestroy(  mp4_track_t * );
125
126 static int  MP4_TrackSelect ( demux_t *, mp4_track_t *, mtime_t );
127 static void MP4_TrackUnselect(demux_t *, mp4_track_t * );
128
129 static int  MP4_TrackSeek   ( demux_t *, mp4_track_t *, mtime_t );
130
131 static uint64_t MP4_TrackGetPos    ( mp4_track_t * );
132 static uint32_t MP4_TrackSampleSize( mp4_track_t *, uint32_t * );
133 static int      MP4_TrackNextSample( demux_t *, mp4_track_t *, uint32_t );
134 static void     MP4_TrackSetELST( demux_t *, mp4_track_t *, int64_t );
135
136 static void     MP4_UpdateSeekpoint( demux_t * );
137 static const char *MP4_ConvertMacCode( uint16_t );
138
139 static MP4_Box_t * MP4_GetTrexByTrackID( MP4_Box_t *p_moov, const uint32_t i_id );
140
141 static bool AddFragment( demux_t *p_demux, MP4_Box_t *p_moox );
142 static int  ProbeFragments( demux_t *p_demux, bool b_force );
143 static int  ProbeIndex( demux_t *p_demux );
144 static mp4_fragment_t *GetFragmentByPos( demux_t *p_demux, uint64_t i_pos, bool b_exact );
145 static mp4_fragment_t *GetFragmentByTime( demux_t *p_demux, const mtime_t i_time );
146
147 static int LeafIndexGetMoofPosByTime( demux_t *p_demux, const mtime_t i_target_time,
148                                       uint64_t *pi_pos, mtime_t *pi_mooftime );
149 static mtime_t LeafGetFragmentTimeOffset( demux_t *p_demux, mp4_fragment_t * );
150 static int LeafGetTrackAndChunkByMOOVPos( demux_t *p_demux, uint64_t *pi_pos,
151                                       mp4_track_t **pp_tk, unsigned int *pi_chunk );
152 static int LeafMapTrafTrunContextes( demux_t *p_demux, MP4_Box_t *p_moof );
153
154 /* Helpers */
155
156 static uint32_t stream_ReadU32( stream_t *s, void *p_read, uint32_t i_toread )
157 {
158     uint32_t i_return = 0;
159     if ( i_toread > INT32_MAX )
160     {
161         i_return = stream_Read( s, p_read, INT32_MAX );
162         if ( i_return < INT32_MAX )
163             return i_return;
164         else
165             i_toread -= INT32_MAX;
166     }
167     i_return += stream_Read( s, (uint8_t *)p_read + i_return, (int32_t) i_toread );
168     return i_return;
169 }
170
171 static bool MP4_stream_Tell( stream_t *s, uint64_t *pi_pos )
172 {
173     int64_t i_pos = stream_Tell( s );
174     if ( i_pos < 0 )
175         return false;
176     else
177     {
178         *pi_pos = (uint64_t) i_pos;
179         return true;
180     }
181 }
182
183 static MP4_Box_t * MP4_GetTrexByTrackID( MP4_Box_t *p_moov, const uint32_t i_id )
184 {
185     MP4_Box_t *p_trex = MP4_BoxGet( p_moov, "mvex/trex" );
186     while( p_trex )
187     {
188         if ( p_trex->i_type == ATOM_trex && BOXDATA(p_trex)->i_track_ID == i_id )
189                 break;
190         else
191             p_trex = p_trex->p_next;
192     }
193     return p_trex;
194 }
195
196 static MP4_Box_t * MP4_GetTrakByTrackID( MP4_Box_t *p_moov, const uint32_t i_id )
197 {
198     MP4_Box_t *p_trak = MP4_BoxGet( p_moov, "trak" );
199     MP4_Box_t *p_tkhd;
200     while( p_trak )
201     {
202         if( p_trak->i_type == ATOM_trak &&
203             (p_tkhd = MP4_BoxGet( p_trak, "tkhd" )) &&
204             BOXDATA(p_tkhd)->i_track_ID == i_id )
205                 break;
206         else
207             p_trak = p_trak->p_next;
208     }
209     return p_trak;
210 }
211
212 /* Return time in microsecond of a track */
213 static inline int64_t MP4_TrackGetDTS( demux_t *p_demux, mp4_track_t *p_track )
214 {
215     demux_sys_t *p_sys = p_demux->p_sys;
216     mp4_chunk_t chunk;
217     if( p_sys->b_fragmented )
218         chunk = *p_track->cchunk;
219     else
220         chunk = p_track->chunk[p_track->i_chunk];
221
222     unsigned int i_index = 0;
223     unsigned int i_sample = p_track->i_sample - chunk.i_sample_first;
224     int64_t i_dts = chunk.i_first_dts;
225
226     while( i_sample > 0 )
227     {
228         if( i_sample > chunk.p_sample_count_dts[i_index] )
229         {
230             i_dts += chunk.p_sample_count_dts[i_index] *
231                 chunk.p_sample_delta_dts[i_index];
232             i_sample -= chunk.p_sample_count_dts[i_index];
233             i_index++;
234         }
235         else
236         {
237             i_dts += i_sample * chunk.p_sample_delta_dts[i_index];
238             break;
239         }
240     }
241
242     /* now handle elst */
243     if( p_track->p_elst )
244     {
245         demux_sys_t         *p_sys = p_demux->p_sys;
246         MP4_Box_data_elst_t *elst = p_track->BOXDATA(p_elst);
247
248         /* convert to offset */
249         if( ( elst->i_media_rate_integer[p_track->i_elst] > 0 ||
250               elst->i_media_rate_fraction[p_track->i_elst] > 0 ) &&
251             elst->i_media_time[p_track->i_elst] > 0 )
252         {
253             i_dts -= elst->i_media_time[p_track->i_elst];
254         }
255
256         /* add i_elst_time */
257         i_dts += p_track->i_elst_time * p_track->i_timescale /
258             p_sys->i_timescale;
259
260         if( i_dts < 0 ) i_dts = 0;
261     }
262
263     return CLOCK_FREQ * i_dts / p_track->i_timescale;
264 }
265
266 static inline int64_t MP4_TrackGetPTSDelta( demux_t *p_demux, mp4_track_t *p_track )
267 {
268     demux_sys_t *p_sys = p_demux->p_sys;
269     mp4_chunk_t *ck;
270     if( p_sys->b_fragmented )
271         ck = p_track->cchunk;
272     else
273         ck = &p_track->chunk[p_track->i_chunk];
274
275     unsigned int i_index = 0;
276     unsigned int i_sample = p_track->i_sample - ck->i_sample_first;
277
278     if( ck->p_sample_count_pts == NULL || ck->p_sample_offset_pts == NULL )
279         return -1;
280
281     for( i_index = 0;; i_index++ )
282     {
283         if( i_sample < ck->p_sample_count_pts[i_index] )
284             return ck->p_sample_offset_pts[i_index] * CLOCK_FREQ /
285                    (int64_t)p_track->i_timescale;
286
287         i_sample -= ck->p_sample_count_pts[i_index];
288     }
289 }
290
291 static inline int64_t MP4_GetMoviePTS(demux_sys_t *p_sys )
292 {
293     return CLOCK_FREQ * p_sys->i_time / p_sys->i_timescale;
294 }
295
296 static void LoadChapter( demux_t  *p_demux );
297
298 static int LoadInitFrag( demux_t *p_demux )
299 {
300     demux_sys_t *p_sys = p_demux->p_sys;
301
302     if( p_sys->b_smooth ) /* Smooth Streaming */
303     {
304         if( ( p_sys->p_root = MP4_BoxGetSmooBox( p_demux->s ) ) == NULL )
305         {
306             goto LoadInitFragError;
307         }
308         else
309         {
310             MP4_Box_t *p_smoo = MP4_BoxGet( p_sys->p_root, "uuid" );
311             if( !p_smoo || CmpUUID( &p_smoo->i_uuid, &SmooBoxUUID ) )
312                 goto LoadInitFragError;
313             /* Get number of tracks */
314             p_sys->i_tracks = 0;
315             for( int i = 0; i < 3; i++ )
316             {
317                 MP4_Box_t *p_stra = MP4_BoxGet( p_smoo, "uuid[%d]", i );
318                 if( p_stra && BOXDATA(p_stra)->i_track_ID )
319                     p_sys->i_tracks++;
320                 /* Get timescale and duration of the video track; */
321                 if( p_sys->i_timescale == 0 )
322                 {
323                     p_sys->i_timescale = BOXDATA(p_stra)->i_timescale;
324                     p_sys->i_duration = BOXDATA(p_stra)->i_duration;
325                     p_sys->i_overall_duration = BOXDATA(p_stra)->i_duration;
326                     if( p_sys->i_timescale == 0 )
327                     {
328                         msg_Err( p_demux, "bad timescale" );
329                         goto LoadInitFragError;
330                     }
331                 }
332             }
333         }
334     }
335     else
336     {
337         /* Load all boxes ( except raw data ) */
338         if( ( p_sys->p_root = MP4_BoxGetRoot( p_demux->s ) ) == NULL )
339         {
340             goto LoadInitFragError;
341         }
342     }
343     return VLC_SUCCESS;
344
345 LoadInitFragError:
346     msg_Warn( p_demux, "MP4 plugin discarded (not a valid initialization chunk)" );
347     return VLC_EGENERIC;
348 }
349
350 static int InitTracks( demux_t *p_demux )
351 {
352     demux_sys_t *p_sys = p_demux->p_sys;
353
354     p_sys->track = calloc( p_sys->i_tracks, sizeof( mp4_track_t ) );
355     if( p_sys->track == NULL )
356         return VLC_EGENERIC;
357
358     if( p_sys->b_fragmented )
359     {
360         mp4_track_t *p_track;
361         for( uint16_t i = 0; i < p_sys->i_tracks; i++ )
362         {
363             p_track = &p_sys->track[i];
364             p_track->cchunk = calloc( 1, sizeof( mp4_chunk_t ) );
365             if( unlikely( !p_track->cchunk ) )
366             {
367                 free( p_sys->track );
368                 return VLC_EGENERIC;
369             }
370         }
371     }
372     return VLC_SUCCESS;
373 }
374
375 static void CreateTracksFromSmooBox( demux_t *p_demux )
376 {
377     demux_sys_t *p_sys = p_demux->p_sys;
378
379     MP4_Box_t *p_smoo = MP4_BoxGet( p_sys->p_root, "uuid" );
380     mp4_track_t *p_track;
381     int j = 0;
382     for( int i = 0; i < 3; i++ )
383     {
384         MP4_Box_t *p_stra = MP4_BoxGet( p_smoo, "uuid[%d]", i );
385         if( !p_stra || BOXDATA(p_stra)->i_track_ID == 0 )
386             continue;
387         else
388         {
389             p_track = &p_sys->track[j]; j++;
390             MP4_frg_TrackCreate( p_demux, p_track, p_stra );
391             p_track->p_es = es_out_Add( p_demux->out, &p_track->fmt );
392         }
393     }
394 }
395
396 /*****************************************************************************
397  * Open: check file and initializes MP4 structures
398  *****************************************************************************/
399 static int Open( vlc_object_t * p_this )
400 {
401     demux_t  *p_demux = (demux_t *)p_this;
402     demux_sys_t     *p_sys;
403
404     const uint8_t   *p_peek;
405
406     MP4_Box_t       *p_ftyp;
407     MP4_Box_t       *p_rmra;
408     MP4_Box_t       *p_mvhd;
409     MP4_Box_t       *p_trak;
410
411     unsigned int    i;
412     bool      b_enabled_es;
413
414     /* A little test to see if it could be a mp4 */
415     if( stream_Peek( p_demux->s, &p_peek, 11 ) < 11 ) return VLC_EGENERIC;
416
417     switch( VLC_FOURCC( p_peek[4], p_peek[5], p_peek[6], p_peek[7] ) )
418     {
419         case ATOM_moov:
420         case ATOM_foov:
421         case ATOM_moof:
422         case ATOM_mdat:
423         case ATOM_udta:
424         case ATOM_free:
425         case ATOM_skip:
426         case ATOM_wide:
427         case ATOM_uuid:
428         case VLC_FOURCC( 'p', 'n', 'o', 't' ):
429             break;
430         case ATOM_ftyp:
431             /* We don't yet support f4v, but avformat does. */
432             if( p_peek[8] == 'f' && p_peek[9] == '4' && p_peek[10] == 'v' )
433                 return VLC_EGENERIC;
434             break;
435          default:
436             return VLC_EGENERIC;
437     }
438
439     /* create our structure that will contains all data */
440     p_sys = calloc( 1, sizeof( demux_sys_t ) );
441     if ( !p_sys )
442         return VLC_EGENERIC;
443
444     /* I need to seek */
445     stream_Control( p_demux->s, STREAM_CAN_SEEK, &p_sys->b_seekable );
446     if( !p_sys->b_seekable )
447     {
448         msg_Warn( p_demux, "MP4 plugin discarded (not seekable)" );
449         free( p_sys );
450         return VLC_EGENERIC;
451     }
452     stream_Control( p_demux->s, STREAM_CAN_FASTSEEK, &p_sys->b_fastseekable );
453
454     /*Set exported functions */
455     p_demux->pf_demux = Demux;
456     p_demux->pf_control = Control;
457
458     p_demux->p_sys = p_sys;
459
460     if( stream_Peek( p_demux->s, &p_peek, 24 ) < 24 ) return VLC_EGENERIC;
461     if( !CmpUUID( (UUID_t *)(p_peek + 8), &SmooBoxUUID ) )
462     {
463         p_sys->b_smooth = true;
464         p_sys->b_fragmented = true;
465     }
466
467     if( LoadInitFrag( p_demux ) != VLC_SUCCESS )
468         goto error;
469
470     if( MP4_BoxCount( p_sys->p_root, "/moov/mvex" ) > 0 )
471     {
472         if ( p_sys->b_seekable )
473         {
474             /* Probe remaining to check if there's really fragments
475                or if that file is just ready to append fragments */
476             ProbeFragments( p_demux, false );
477             p_sys->b_fragmented = !!MP4_BoxCount( p_sys->p_root, "/moof" );
478         }
479         else
480             p_sys->b_fragmented = true;
481
482         if ( p_sys->b_fragmented && !p_sys->i_overall_duration )
483             ProbeFragments( p_demux, true );
484     }
485
486     if ( !p_sys->moovfragment.p_moox )
487         AddFragment( p_demux, MP4_BoxGet( p_sys->p_root, "/moov" ) );
488
489     /* we always need a moov entry, but smooth has a workaround */
490     if ( !p_sys->moovfragment.p_moox && !p_sys->b_smooth )
491         goto error;
492
493     if ( p_sys->b_smooth )
494     {
495         p_demux->pf_demux = DemuxFrg;
496     }
497     else if( p_sys->b_fragmented )
498     {
499         p_demux->pf_demux = DemuxAsLeaf;
500     }
501
502     if( p_sys->b_smooth )
503     {
504         if( InitTracks( p_demux ) != VLC_SUCCESS )
505             goto error;
506         CreateTracksFromSmooBox( p_demux );
507         return VLC_SUCCESS;
508     }
509
510     MP4_BoxDumpStructure( p_demux->s, p_sys->p_root );
511
512     if( ( p_ftyp = MP4_BoxGet( p_sys->p_root, "/ftyp" ) ) )
513     {
514         switch( BOXDATA(p_ftyp)->i_major_brand )
515         {
516             case( ATOM_isom ):
517                 msg_Dbg( p_demux,
518                          "ISO Media file (isom) version %d.",
519                          BOXDATA(p_ftyp)->i_minor_version );
520                 break;
521             case( ATOM_3gp4 ):
522             case( VLC_FOURCC( '3', 'g', 'p', '5' ) ):
523             case( VLC_FOURCC( '3', 'g', 'p', '6' ) ):
524             case( VLC_FOURCC( '3', 'g', 'p', '7' ) ):
525                 msg_Dbg( p_demux, "3GPP Media file Release: %c",
526 #ifdef WORDS_BIGENDIAN
527                         BOXDATA(p_ftyp)->i_major_brand
528 #else
529                         BOXDATA(p_ftyp)->i_major_brand >> 24
530 #endif
531                         );
532                 break;
533             case( VLC_FOURCC( 'q', 't', ' ', ' ') ):
534                 msg_Dbg( p_demux, "Apple QuickTime file" );
535                 break;
536             case( VLC_FOURCC( 'i', 's', 'm', 'l') ):
537                 msg_Dbg( p_demux, "PIFF (= isml = fMP4) file" );
538                 break;
539             default:
540                 msg_Dbg( p_demux,
541                          "unrecognized major file specification (%4.4s).",
542                           (char*)&BOXDATA(p_ftyp)->i_major_brand );
543                 break;
544         }
545     }
546     else
547     {
548         msg_Dbg( p_demux, "file type box missing (assuming ISO Media file)" );
549     }
550
551     /* the file need to have one moov box */
552     p_sys->moovfragment.p_moox = MP4_BoxGet( p_sys->p_root, "/moov", 0 );
553     if( !p_sys->moovfragment.p_moox )
554     {
555         MP4_Box_t *p_foov = MP4_BoxGet( p_sys->p_root, "/foov" );
556
557         if( !p_foov )
558         {
559             msg_Err( p_demux, "MP4 plugin discarded (no moov,foov,moof box)" );
560             goto error;
561         }
562         /* we have a free box as a moov, rename it */
563         p_foov->i_type = ATOM_moov;
564         p_sys->moovfragment.p_moox = p_foov;
565     }
566
567     if( ( p_rmra = MP4_BoxGet( p_sys->p_root,  "/moov/rmra" ) ) )
568     {
569         int        i_count = MP4_BoxCount( p_rmra, "rmda" );
570         int        i;
571
572         msg_Dbg( p_demux, "detected playlist mov file (%d ref)", i_count );
573
574         input_thread_t *p_input = demux_GetParentInput( p_demux );
575         input_item_t *p_current = input_GetItem( p_input );
576
577         input_item_node_t *p_subitems = input_item_node_Create( p_current );
578
579         for( i = 0; i < i_count; i++ )
580         {
581             MP4_Box_t *p_rdrf = MP4_BoxGet( p_rmra, "rmda[%d]/rdrf", i );
582             char      *psz_ref;
583             uint32_t  i_ref_type;
584
585             if( !p_rdrf || !( psz_ref = strdup( BOXDATA(p_rdrf)->psz_ref ) ) )
586             {
587                 continue;
588             }
589             i_ref_type = BOXDATA(p_rdrf)->i_ref_type;
590
591             msg_Dbg( p_demux, "new ref=`%s' type=%4.4s",
592                      psz_ref, (char*)&i_ref_type );
593
594             if( i_ref_type == VLC_FOURCC( 'u', 'r', 'l', ' ' ) )
595             {
596                 if( strstr( psz_ref, "qt5gateQT" ) )
597                 {
598                     msg_Dbg( p_demux, "ignoring pseudo ref =`%s'", psz_ref );
599                     continue;
600                 }
601                 if( !strncmp( psz_ref, "http://", 7 ) ||
602                     !strncmp( psz_ref, "rtsp://", 7 ) )
603                 {
604                     ;
605                 }
606                 else
607                 {
608                     char *psz_absolute;
609                     char *psz_path = strdup( p_demux->psz_location );
610                     char *end = strrchr( psz_path, '/' );
611                     if( end ) end[1] = '\0';
612                     else *psz_path = '\0';
613
614                     if( asprintf( &psz_absolute, "%s://%s%s",
615                                   p_demux->psz_access, psz_path, psz_ref ) < 0 )
616                     {
617                         free( psz_ref );
618                         free( psz_path );
619                         input_item_node_Delete( p_subitems );
620                         vlc_object_release( p_input) ;
621                         return VLC_ENOMEM;
622                     }
623
624                     free( psz_ref );
625                     psz_ref = psz_absolute;
626                     free( psz_path );
627                 }
628                 msg_Dbg( p_demux, "adding ref = `%s'", psz_ref );
629                 input_item_t *p_item = input_item_New( psz_ref, NULL );
630                 input_item_CopyOptions( p_current, p_item );
631                 input_item_node_AppendItem( p_subitems, p_item );
632                 vlc_gc_decref( p_item );
633             }
634             else
635             {
636                 msg_Err( p_demux, "unknown ref type=%4.4s FIXME (send a bug report)",
637                          (char*)&BOXDATA(p_rdrf)->i_ref_type );
638             }
639             free( psz_ref );
640         }
641         input_item_node_PostAndDelete( p_subitems );
642         vlc_object_release( p_input );
643     }
644
645     if( !(p_mvhd = MP4_BoxGet( p_sys->p_root, "/moov/mvhd" ) ) )
646     {
647         if( !p_rmra )
648         {
649             msg_Err( p_demux, "cannot find /moov/mvhd" );
650             goto error;
651         }
652         else
653         {
654             msg_Warn( p_demux, "cannot find /moov/mvhd (pure ref file)" );
655             p_demux->pf_demux = DemuxRef;
656             return VLC_SUCCESS;
657         }
658     }
659     else
660     {
661         p_sys->i_timescale = BOXDATA(p_mvhd)->i_timescale;
662         if( p_sys->i_timescale == 0 )
663         {
664             msg_Err( p_this, "bad timescale" );
665             goto error;
666         }
667     }
668
669     if ( p_sys->i_overall_duration == 0 )
670     {
671         /* Try in mehd if fragmented */
672         MP4_Box_t *p_mehd = MP4_BoxGet( p_demux->p_sys->p_root, "moov/mvex/mehd");
673         if ( p_mehd )
674             p_sys->i_overall_duration = p_mehd->data.p_mehd->i_fragment_duration;
675         else
676             p_sys->i_overall_duration = p_sys->moovfragment.i_duration;
677     }
678
679     if( !( p_sys->i_tracks = MP4_BoxCount( p_sys->p_root, "/moov/trak" ) ) )
680     {
681         msg_Err( p_demux, "cannot find any /moov/trak" );
682         goto error;
683     }
684     msg_Dbg( p_demux, "found %d track%c",
685                         p_sys->i_tracks,
686                         p_sys->i_tracks ? 's':' ' );
687
688     if( InitTracks( p_demux ) != VLC_SUCCESS )
689         goto error;
690
691     /* Search the first chap reference (like quicktime) and
692      * check that at least 1 stream is enabled */
693     p_sys->p_tref_chap = NULL;
694     b_enabled_es = false;
695     for( i = 0; i < p_sys->i_tracks; i++ )
696     {
697         MP4_Box_t *p_trak = MP4_BoxGet( p_sys->p_root, "/moov/trak[%d]", i );
698
699
700         MP4_Box_t *p_tkhd = MP4_BoxGet( p_trak, "tkhd" );
701         if( p_tkhd && (BOXDATA(p_tkhd)->i_flags&MP4_TRACK_ENABLED) )
702             b_enabled_es = true;
703
704         MP4_Box_t *p_chap = MP4_BoxGet( p_trak, "tref/chap", i );
705         if( p_chap && p_chap->data.p_tref_generic->i_entry_count > 0 && !p_sys->p_tref_chap )
706             p_sys->p_tref_chap = p_chap;
707     }
708
709     /* now process each track and extract all useful information */
710     for( i = 0; i < p_sys->i_tracks; i++ )
711     {
712         p_trak = MP4_BoxGet( p_sys->p_root, "/moov/trak[%d]", i );
713         MP4_TrackCreate( p_demux, &p_sys->track[i], p_trak, !b_enabled_es );
714
715         if( p_sys->track[i].b_ok && !p_sys->track[i].b_chapter )
716         {
717             const char *psz_cat;
718             switch( p_sys->track[i].fmt.i_cat )
719             {
720                 case( VIDEO_ES ):
721                     psz_cat = "video";
722                     break;
723                 case( AUDIO_ES ):
724                     psz_cat = "audio";
725                     break;
726                 case( SPU_ES ):
727                     psz_cat = "subtitle";
728                     break;
729
730                 default:
731                     psz_cat = "unknown";
732                     break;
733             }
734
735             msg_Dbg( p_demux, "adding track[Id 0x%x] %s (%s) language %s",
736                      p_sys->track[i].i_track_ID, psz_cat,
737                      p_sys->track[i].b_enable ? "enable":"disable",
738                      p_sys->track[i].fmt.psz_language ?
739                      p_sys->track[i].fmt.psz_language : "undef" );
740         }
741         else if( p_sys->track[i].b_ok && p_sys->track[i].b_chapter )
742         {
743             msg_Dbg( p_demux, "using track[Id 0x%x] for chapter language %s",
744                      p_sys->track[i].i_track_ID,
745                      p_sys->track[i].fmt.psz_language ?
746                      p_sys->track[i].fmt.psz_language : "undef" );
747         }
748         else
749         {
750             msg_Dbg( p_demux, "ignoring track[Id 0x%x]",
751                      p_sys->track[i].i_track_ID );
752         }
753     }
754
755     mp4_fragment_t *p_fragment = &p_sys->moovfragment;
756     while ( p_fragment )
757     {
758         msg_Dbg( p_demux, "fragment offset %"PRId64", data %"PRIu64"<->%"PRIu64", duration %"PRId64,
759                  p_fragment->p_moox->i_pos, p_fragment->i_chunk_range_min_offset,
760                  p_fragment->i_chunk_range_max_offset, CLOCK_FREQ * p_fragment->i_duration / p_sys->i_timescale );
761         p_fragment = p_fragment->p_next;
762     }
763
764     /* */
765     LoadChapter( p_demux );
766
767     return VLC_SUCCESS;
768
769 error:
770     if( p_sys->p_root )
771     {
772         MP4_BoxFree( p_demux->s, p_sys->p_root );
773     }
774     free( p_sys );
775     return VLC_EGENERIC;
776 }
777
778 /*****************************************************************************
779  * Demux: read packet and send them to decoders
780  *****************************************************************************
781  * TODO check for newly selected track (ie audio upt to now )
782  *****************************************************************************/
783 static int Demux( demux_t *p_demux )
784 {
785     demux_sys_t *p_sys = p_demux->p_sys;
786     unsigned int i_track;
787
788
789     unsigned int i_track_selected;
790
791     /* check for newly selected/unselected track */
792     for( i_track = 0, i_track_selected = 0; i_track < p_sys->i_tracks;
793          i_track++ )
794     {
795         mp4_track_t *tk = &p_sys->track[i_track];
796         bool b;
797
798         if( !tk->b_ok || tk->b_chapter ||
799             ( tk->b_selected && tk->i_sample >= tk->i_sample_count ) )
800         {
801             continue;
802         }
803
804         es_out_Control( p_demux->out, ES_OUT_GET_ES_STATE, tk->p_es, &b );
805
806         if( tk->b_selected && !b )
807         {
808             MP4_TrackUnselect( p_demux, tk );
809         }
810         else if( !tk->b_selected && b)
811         {
812             MP4_TrackSelect( p_demux, tk, MP4_GetMoviePTS( p_sys ) );
813         }
814
815         if( tk->b_selected )
816         {
817             i_track_selected++;
818         }
819     }
820
821     if( i_track_selected <= 0 )
822     {
823         p_sys->i_time += __MAX( p_sys->i_timescale / 10 , 1 );
824         if( p_sys->i_timescale > 0 )
825         {
826             int64_t i_length = CLOCK_FREQ *
827                                (mtime_t)p_sys->moovfragment.i_duration /
828                                (mtime_t)p_sys->i_timescale;
829             if( MP4_GetMoviePTS( p_sys ) >= i_length )
830                 return 0;
831             return 1;
832         }
833
834         msg_Warn( p_demux, "no track selected, exiting..." );
835         return 0;
836     }
837
838     /* */
839     MP4_UpdateSeekpoint( p_demux );
840
841     /* first wait for the good time to read a packet */
842     p_sys->i_pcr = MP4_GetMoviePTS( p_sys );
843
844     bool b_data_sent = false;
845
846     /* Find next track matching contiguous data */
847     mp4_track_t *tk = NULL;
848     uint64_t i_candidate_pos = UINT64_MAX;
849     for( i_track = 0; i_track < p_sys->i_tracks; i_track++ )
850     {
851         mp4_track_t *tk_tmp = &p_sys->track[i_track];
852         if( !tk_tmp->b_ok || tk_tmp->b_chapter || !tk_tmp->b_selected || tk_tmp->i_sample >= tk_tmp->i_sample_count )
853             continue;
854
855         uint64_t i_pos = MP4_TrackGetPos( tk_tmp );
856         if ( i_pos <= i_candidate_pos )
857         {
858             i_candidate_pos = i_pos;
859             tk = tk_tmp;
860         }
861     }
862
863     if ( !tk )
864     {
865         msg_Dbg( p_demux, "Could not select track by data position" );
866         goto end;
867     }
868
869 #if 0
870     msg_Dbg( p_demux, "tk(%i)=%"PRId64" mv=%"PRId64" pos=%"PRIu64, i_track,
871              MP4_TrackGetDTS( p_demux, tk ),
872              MP4_GetMoviePTS( p_sys ), i_candidate_pos );
873 #endif
874
875     uint32_t i_nb_samples = 0;
876     uint32_t i_samplessize = MP4_TrackSampleSize( tk, &i_nb_samples );
877     if( i_samplessize > 0 )
878     {
879         block_t *p_block;
880         int64_t i_delta;
881         uint64_t i_current_pos;
882
883         /* go,go go ! */
884         if ( !MP4_stream_Tell( p_demux->s, &i_current_pos ) )
885             goto end;
886
887         if( i_current_pos != i_candidate_pos )
888         {
889             if( stream_Seek( p_demux->s, i_candidate_pos ) )
890             {
891                 msg_Warn( p_demux, "track[0x%x] will be disabled (eof?)",
892                           tk->i_track_ID );
893                 MP4_TrackUnselect( p_demux, tk );
894                 goto end;
895             }
896         }
897
898         /* now read pes */
899         if( !(p_block = stream_Block( p_demux->s, i_samplessize )) )
900         {
901             msg_Warn( p_demux, "track[0x%x] will be disabled (eof?)",
902                       tk->i_track_ID );
903             MP4_TrackUnselect( p_demux, tk );
904             goto end;
905         }
906         else if( tk->fmt.i_cat == SPU_ES )
907         {
908             if ( tk->fmt.i_codec != VLC_CODEC_TX3G &&
909                  tk->fmt.i_codec != VLC_CODEC_SPU )
910                 p_block->i_buffer = 0;
911         }
912
913         /* dts */
914         p_block->i_dts = VLC_TS_0 + MP4_TrackGetDTS( p_demux, tk );
915         /* pts */
916         i_delta = MP4_TrackGetPTSDelta( p_demux, tk );
917         if( i_delta != -1 )
918             p_block->i_pts = p_block->i_dts + i_delta;
919         else if( tk->fmt.i_cat != VIDEO_ES )
920             p_block->i_pts = p_block->i_dts;
921         else
922             p_block->i_pts = VLC_TS_INVALID;
923
924         if ( !b_data_sent )
925         {
926             es_out_Control( p_demux->out, ES_OUT_SET_PCR, VLC_TS_0 + p_sys->i_pcr );
927             b_data_sent = true;
928         }
929         es_out_Send( p_demux->out, tk->p_es, p_block );
930
931         /* Next sample */
932         MP4_TrackNextSample( p_demux, tk, i_nb_samples );
933     }
934
935 end:
936     if ( b_data_sent )
937     {
938         p_sys->i_pcr = INT64_MAX;
939         for( i_track = 0; i_track < p_sys->i_tracks; i_track++ )
940         {
941             mp4_track_t *tk = &p_sys->track[i_track];
942             if ( !tk->b_ok || !tk->b_selected ) continue;
943             p_sys->i_pcr = __MIN( MP4_TrackGetDTS( p_demux, tk ), p_sys->i_pcr );
944             p_sys->i_time = p_sys->i_pcr * p_sys->i_timescale / CLOCK_FREQ;
945         }
946     }
947
948     return b_data_sent;
949 }
950
951 static void MP4_UpdateSeekpoint( demux_t *p_demux )
952 {
953     demux_sys_t *p_sys = p_demux->p_sys;
954     int64_t i_time;
955     int i;
956     if( !p_sys->p_title )
957         return;
958     i_time = MP4_GetMoviePTS( p_sys );
959     for( i = 0; i < p_sys->p_title->i_seekpoint; i++ )
960     {
961         if( i_time < p_sys->p_title->seekpoint[i]->i_time_offset )
962             break;
963     }
964     i--;
965
966     if( i != p_demux->info.i_seekpoint && i >= 0 )
967     {
968         p_demux->info.i_seekpoint = i;
969         p_demux->info.i_update |= INPUT_UPDATE_SEEKPOINT;
970     }
971 }
972 /*****************************************************************************
973  * Seek: Go to i_date
974 ******************************************************************************/
975 static int Seek( demux_t *p_demux, mtime_t i_date )
976 {
977     demux_sys_t *p_sys = p_demux->p_sys;
978     unsigned int i_track;
979
980     /* First update global time */
981     p_sys->i_time = i_date * p_sys->i_timescale / CLOCK_FREQ;
982     p_sys->i_pcr  = VLC_TS_INVALID;
983
984     /* Now for each stream try to go to this time */
985     for( i_track = 0; i_track < p_sys->i_tracks; i_track++ )
986     {
987         mp4_track_t *tk = &p_sys->track[i_track];
988         MP4_TrackSeek( p_demux, tk, i_date );
989     }
990     MP4_UpdateSeekpoint( p_demux );
991
992     es_out_Control( p_demux->out, ES_OUT_SET_NEXT_DISPLAY_TIME, i_date );
993
994     return VLC_SUCCESS;
995 }
996
997 static int LeafSeekIntoFragment( demux_t *p_demux, mp4_fragment_t *p_fragment )
998 {
999     demux_sys_t *p_sys = p_demux->p_sys;
1000     uint64_t i64 = p_fragment->i_chunk_range_min_offset;
1001
1002     if ( p_fragment->p_moox->i_type == ATOM_moov )
1003     {
1004         mp4_track_t *p_track;
1005         unsigned int i_chunk;
1006         int i_ret = LeafGetTrackAndChunkByMOOVPos( p_demux, &i64, &p_track, &i_chunk );
1007         if ( i_ret == VLC_EGENERIC )
1008         {
1009             msg_Dbg( p_demux, "moov seek failed to identify %"PRIu64, i64 );
1010             return i_ret;
1011         }
1012         msg_Dbg( p_demux, "moov seeking to %"PRIu64, i64 );
1013     }
1014     else
1015     {
1016         i64 = p_fragment->i_chunk_range_min_offset;
1017         msg_Dbg( p_demux, "moof seeking to %"PRIu64, i64 );
1018     }
1019
1020     if( stream_Seek( p_demux->s, i64 ) )
1021     {
1022         msg_Err( p_demux, "seek failed to %"PRIu64, i64 );
1023         return VLC_EGENERIC;
1024     }
1025
1026     /* map context */
1027     p_sys->context.p_fragment = p_fragment;
1028     p_sys->context.i_current_box_type = ATOM_mdat;
1029     LeafMapTrafTrunContextes( p_demux, p_fragment->p_moox );
1030     p_sys->context.i_mdatbytesleft = p_fragment->i_chunk_range_max_offset - i64;
1031
1032     mtime_t i_time_base = LeafGetFragmentTimeOffset( p_demux, p_fragment );
1033     for( unsigned int i_track = 0; i_track < p_sys->i_tracks; i_track++ )
1034     {
1035         p_sys->track[i_track].i_time = i_time_base * p_sys->track[i_track].i_timescale / p_sys->i_timescale;
1036     }
1037     p_sys->i_time = i_time_base;
1038     p_sys->i_pcr  = VLC_TS_INVALID;
1039
1040     return VLC_SUCCESS;
1041 }
1042
1043 static int LeafSeekToTime( demux_t *p_demux, mtime_t i_nztime )
1044 {
1045     demux_sys_t *p_sys = p_demux->p_sys;
1046     mp4_fragment_t *p_fragment;
1047     uint64_t i64 = 0;
1048     if ( !p_sys->i_timescale || !p_sys->i_overall_duration || !p_sys->b_seekable )
1049          return VLC_EGENERIC;
1050
1051     if ( !p_sys->b_fragments_probed && !p_sys->b_index_probed && p_sys->b_seekable )
1052     {
1053         ProbeIndex( p_demux );
1054         p_sys->b_index_probed = true;
1055     }
1056
1057     p_fragment = GetFragmentByTime( p_demux, i_nztime );
1058     if ( !p_fragment )
1059     {
1060         mtime_t i_mooftime;
1061         msg_Dbg( p_demux, "seek can't find matching fragment for %"PRId64", trying index", i_nztime );
1062         if ( LeafIndexGetMoofPosByTime( p_demux, i_nztime, &i64, &i_mooftime ) == VLC_SUCCESS )
1063         {
1064             msg_Dbg( p_demux, "seek trying to go to unknown but indexed fragment at %"PRId64, i64 );
1065             if( stream_Seek( p_demux->s, i64 ) )
1066             {
1067                 msg_Err( p_demux, "seek to moof failed %"PRId64, i64 );
1068                 return VLC_EGENERIC;
1069             }
1070             p_sys->context.i_current_box_type = 0;
1071             p_sys->context.i_mdatbytesleft = 0;
1072             p_sys->context.p_fragment = NULL;
1073             for( unsigned int i_track = 0; i_track < p_sys->i_tracks; i_track++ )
1074             {
1075                 p_sys->track[i_track].i_time = i_mooftime / CLOCK_FREQ * p_sys->track[i_track].i_timescale;
1076             }
1077             p_sys->i_time = i_mooftime / CLOCK_FREQ * p_sys->i_timescale;
1078             p_sys->i_pcr  = VLC_TS_INVALID;
1079         }
1080         else
1081         {
1082             msg_Warn( p_demux, "seek by index failed" );
1083             return VLC_EGENERIC;
1084         }
1085     }
1086     else
1087     {
1088         msg_Dbg( p_demux, "seeking to fragment data starting at %"PRIu64" for time %"PRId64,
1089                            p_fragment->i_chunk_range_min_offset, i_nztime );
1090         if ( LeafSeekIntoFragment( p_demux, p_fragment ) != VLC_SUCCESS )
1091             return VLC_EGENERIC;
1092     }
1093
1094     /* And set next display time in that trun/fragment */
1095     es_out_Control( p_demux->out, ES_OUT_SET_NEXT_DISPLAY_TIME, VLC_TS_0 + i_nztime );
1096     return VLC_SUCCESS;
1097 }
1098
1099 static int LeafSeekToPos( demux_t *p_demux, double f )
1100 {
1101     demux_sys_t *p_sys = p_demux->p_sys;
1102     if ( !p_sys->b_seekable )
1103         return VLC_EGENERIC;
1104
1105     if ( p_sys->i_timescale && p_sys->i_overall_duration )
1106     {
1107         return LeafSeekToTime( p_demux,
1108                     (mtime_t)( f * CLOCK_FREQ * p_sys->i_overall_duration /
1109                                p_sys->i_timescale ) );
1110     }
1111
1112     if ( !p_sys->b_fragments_probed && !p_sys->b_index_probed && p_sys->b_seekable )
1113     {
1114         ProbeIndex( p_demux );
1115         p_sys->b_index_probed = true;
1116     }
1117
1118     /* Blind seek to pos only */
1119     uint64_t i64 = (uint64_t) stream_Size( p_demux->s ) * f;
1120     mp4_fragment_t *p_fragment = GetFragmentByPos( p_demux, i64, false );
1121     if ( p_fragment )
1122     {
1123         msg_Dbg( p_demux, "Seeking to fragment data starting at %"PRIu64" for pos %"PRIu64,
1124                  p_fragment->i_chunk_range_min_offset, i64 );
1125         return LeafSeekIntoFragment( p_demux, p_fragment );
1126     }
1127     else
1128     {
1129         msg_Dbg( p_demux, "Cant get fragment for data starting at %"PRIu64, i64 );
1130         return VLC_EGENERIC;
1131     }
1132 }
1133
1134 static int MP4_frg_Seek( demux_t *p_demux, double f )
1135 {
1136     demux_sys_t *p_sys = p_demux->p_sys;
1137
1138     int64_t i64 = stream_Size( p_demux->s );
1139     if( stream_Seek( p_demux->s, (int64_t)(i64 * f) ) )
1140     {
1141         return VLC_EGENERIC;
1142     }
1143     else
1144     {
1145         /* update global time */
1146         p_sys->i_time = (uint64_t)(f * (double)p_sys->moovfragment.i_duration);
1147         p_sys->i_pcr  = MP4_GetMoviePTS( p_sys );
1148
1149         for( unsigned i_track = 0; i_track < p_sys->i_tracks; i_track++ )
1150         {
1151             mp4_track_t *tk = &p_sys->track[i_track];
1152
1153             /* We don't want the current chunk to be flushed */
1154             tk->cchunk->i_sample = tk->cchunk->i_sample_count;
1155
1156             /* reset/update some values */
1157             tk->i_sample = tk->i_sample_first = 0;
1158             tk->i_first_dts = p_sys->i_time;
1159
1160             /* We want to discard the current chunk and get the next one at once */
1161             tk->b_has_non_empty_cchunk = false;
1162         }
1163         es_out_Control( p_demux->out, ES_OUT_SET_NEXT_DISPLAY_TIME, p_sys->i_pcr );
1164         return VLC_SUCCESS;
1165     }
1166 }
1167
1168 /*****************************************************************************
1169  * Control:
1170  *****************************************************************************/
1171 static int Control( demux_t *p_demux, int i_query, va_list args )
1172 {
1173     demux_sys_t *p_sys = p_demux->p_sys;
1174
1175     double f, *pf;
1176     int64_t i64, *pi64;
1177
1178     switch( i_query )
1179     {
1180         case DEMUX_GET_POSITION:
1181             pf = (double*)va_arg( args, double * );
1182             if( p_sys->i_overall_duration > 0 )
1183             {
1184                 *pf = (double)p_sys->i_time / (double)p_sys->i_overall_duration;
1185             }
1186             else
1187             {
1188                 *pf = 0.0;
1189             }
1190             return VLC_SUCCESS;
1191
1192         case DEMUX_SET_POSITION:
1193             f = (double)va_arg( args, double );
1194             if ( p_demux->pf_demux == DemuxAsLeaf )
1195                 return LeafSeekToPos( p_demux, f );
1196             else if ( p_demux->pf_demux == DemuxFrg )
1197                 return MP4_frg_Seek( p_demux, f );
1198             else if( p_sys->i_timescale > 0 )
1199             {
1200                 i64 = (int64_t)( f * CLOCK_FREQ *
1201                                  (double)p_sys->i_overall_duration /
1202                                  (double)p_sys->i_timescale );
1203                 return Seek( p_demux, i64 );
1204             }
1205             else return VLC_EGENERIC;
1206
1207         case DEMUX_GET_TIME:
1208             pi64 = (int64_t*)va_arg( args, int64_t * );
1209             if( p_sys->i_timescale > 0 )
1210             {
1211                 *pi64 = CLOCK_FREQ *
1212                         (mtime_t)p_sys->i_time /
1213                         (mtime_t)p_sys->i_timescale;
1214             }
1215             else *pi64 = 0;
1216             return VLC_SUCCESS;
1217
1218         case DEMUX_SET_TIME:
1219             i64 = (int64_t)va_arg( args, int64_t );
1220             if ( p_demux->pf_demux == DemuxAsLeaf )
1221                 return LeafSeekToTime( p_demux, i64 );
1222             else
1223                 return Seek( p_demux, i64 );
1224
1225         case DEMUX_GET_LENGTH:
1226             pi64 = (int64_t*)va_arg( args, int64_t * );
1227             if( p_sys->i_timescale > 0 )
1228             {
1229                 *pi64 = CLOCK_FREQ *
1230                         (mtime_t)p_sys->i_overall_duration /
1231                         (mtime_t)p_sys->i_timescale;
1232             }
1233             else *pi64 = 0;
1234             return VLC_SUCCESS;
1235
1236         case DEMUX_GET_FPS:
1237             pf = (double*)va_arg( args, double* );
1238             *pf = p_sys->f_fps;
1239             return VLC_SUCCESS;
1240
1241         case DEMUX_GET_ATTACHMENTS:
1242         {
1243             input_attachment_t ***ppp_attach = va_arg( args, input_attachment_t*** );
1244             int *pi_int = va_arg( args, int * );
1245
1246             MP4_Box_t  *p_covr = MP4_BoxGet( p_sys->p_root, "/moov/udta/meta/ilst/covr" );
1247             if ( !p_covr ) return VLC_EGENERIC;
1248             MP4_Box_t  *p_box;
1249             int i_count = 0;
1250
1251             for( p_box = p_covr->p_first; p_box != NULL; p_box = p_box->p_next )
1252             {
1253                 if ( p_box->i_type == ATOM_data && p_box->data.p_data->i_blob >= 16 )
1254                     i_count++;
1255             }
1256
1257             if ( i_count == 0 )
1258                 return VLC_EGENERIC;
1259
1260             *ppp_attach = (input_attachment_t**)
1261                     malloc( sizeof(input_attachment_t*) * i_count );
1262             if( !(*ppp_attach) ) return VLC_ENOMEM;
1263             char *psz_mime;
1264             char *psz_filename;
1265             i_count = 0;
1266             for( p_box = p_covr->p_first; p_box != NULL; p_box = p_box->p_next )
1267             {
1268                 if ( p_box->i_type != ATOM_data || p_box->data.p_data->i_blob < 16 )
1269                     continue;
1270
1271                 if ( !memcmp( p_box->data.p_data->p_blob,
1272                               "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A", 8 ) )
1273                 {
1274                     psz_mime = strdup( "image/png" );
1275                 }
1276                 else if ( !memcmp( p_box->data.p_data->p_blob, "\xFF\xD8", 2 ) )
1277                 {
1278                     psz_mime = strdup( "image/jpeg" );
1279                 }
1280                 else
1281                 {
1282                     continue;
1283                 }
1284
1285                 if ( asprintf( &psz_filename, "picture%u", i_count ) >= 0 )
1286                 {
1287                     (*ppp_attach)[i_count++] =
1288                         vlc_input_attachment_New( psz_filename, psz_mime, NULL,
1289                             p_box->data.p_data->p_blob, p_box->data.p_data->i_blob );
1290                     free( psz_filename );
1291                 }
1292
1293                 free( psz_mime );
1294             }
1295
1296             if ( i_count == 0 )
1297             {
1298                 free( *ppp_attach );
1299                 return VLC_EGENERIC;
1300             }
1301
1302             *pi_int = i_count;
1303
1304             return VLC_SUCCESS;
1305         }
1306
1307         case DEMUX_GET_META:
1308         {
1309             vlc_meta_t *p_meta = (vlc_meta_t *)va_arg( args, vlc_meta_t*);
1310             MP4_Box_t  *p_0xa9xxx;
1311
1312             MP4_Box_t *p_covr = MP4_BoxGet( p_sys->p_root, "/moov/udta/meta/ilst/covr/data[0]" );
1313             if ( p_covr )
1314                 vlc_meta_SetArtURL( p_meta, "attachment://picture0" );
1315
1316             MP4_Box_t  *p_udta = MP4_BoxGet( p_sys->p_root, "/moov/udta/meta/ilst" );
1317             if( p_udta == NULL )
1318             {
1319                 p_udta = MP4_BoxGet( p_sys->p_root, "/moov/udta" );
1320                 if( p_udta == NULL && p_covr == NULL )
1321                     return VLC_EGENERIC;
1322                 else
1323                     return VLC_SUCCESS;
1324             }
1325
1326             for( p_0xa9xxx = p_udta->p_first; p_0xa9xxx != NULL;
1327                  p_0xa9xxx = p_0xa9xxx->p_next )
1328             {
1329
1330                 if( !p_0xa9xxx || !BOXDATA(p_0xa9xxx) )
1331                     continue;
1332
1333                 /* FIXME FIXME: should convert from whatever the character
1334                  * encoding of MP4 meta data is to UTF-8. */
1335 #define SET(fct) do { char *psz_utf = strdup( BOXDATA(p_0xa9xxx)->psz_text ? BOXDATA(p_0xa9xxx)->psz_text : "" ); \
1336     if( psz_utf ) { EnsureUTF8( psz_utf );  \
1337                     fct( p_meta, psz_utf ); free( psz_utf ); } } while(0)
1338
1339                 /* XXX Becarefull p_udta can have box that are not 0xa9xx */
1340                 switch( p_0xa9xxx->i_type )
1341                 {
1342                 case ATOM_0xa9nam: /* Full name */
1343                     SET( vlc_meta_SetTitle );
1344                     break;
1345                 case ATOM_0xa9aut:
1346                     SET( vlc_meta_SetArtist );
1347                     break;
1348                 case ATOM_0xa9ART:
1349                     SET( vlc_meta_SetArtist );
1350                     break;
1351                 case ATOM_0xa9cpy:
1352                     SET( vlc_meta_SetCopyright );
1353                     break;
1354                 case ATOM_0xa9day: /* Creation Date */
1355                     SET( vlc_meta_SetDate );
1356                     break;
1357                 case ATOM_0xa9des: /* Description */
1358                     SET( vlc_meta_SetDescription );
1359                     break;
1360                 case ATOM_0xa9gen: /* Genre */
1361                     SET( vlc_meta_SetGenre );
1362                     break;
1363
1364                 case ATOM_gnre:
1365                     if( p_0xa9xxx->data.p_gnre->i_genre <= NUM_GENRES )
1366                         vlc_meta_SetGenre( p_meta, ppsz_genres[p_0xa9xxx->data.p_gnre->i_genre - 1] );
1367                     break;
1368
1369                 case ATOM_0xa9alb: /* Album */
1370                     SET( vlc_meta_SetAlbum );
1371                     break;
1372
1373                 case ATOM_0xa9trk: /* Track */
1374                     SET( vlc_meta_SetTrackNum );
1375                     break;
1376                 case ATOM_trkn:
1377                 {
1378                     char psz_trck[11];
1379                     snprintf( psz_trck, sizeof( psz_trck ), "%i",
1380                               p_0xa9xxx->data.p_trkn->i_track_number );
1381                     vlc_meta_SetTrackNum( p_meta, psz_trck );
1382                     if( p_0xa9xxx->data.p_trkn->i_track_total > 0 )
1383                     {
1384                         snprintf( psz_trck, sizeof( psz_trck ), "%i",
1385                                   p_0xa9xxx->data.p_trkn->i_track_total );
1386                         vlc_meta_Set( p_meta, vlc_meta_TrackTotal, psz_trck );
1387                     }
1388                     break;
1389                 }
1390                 case ATOM_0xa9cmt: /* Commment */
1391                     SET( vlc_meta_SetDescription );
1392                     break;
1393
1394                 case ATOM_0xa9url: /* URL */
1395                     SET( vlc_meta_SetURL );
1396                     break;
1397
1398                 case ATOM_0xa9too: /* Encoder Tool */
1399                 case ATOM_0xa9enc: /* Encoded By */
1400                     SET( vlc_meta_SetEncodedBy );
1401                     break;
1402
1403                 case ATOM_0xa9pub:
1404                     SET( vlc_meta_SetPublisher );
1405                     break;
1406
1407                 case ATOM_0xa9dir:
1408                     SET( vlc_meta_SetDirector );
1409                     break;
1410
1411                 default:
1412                     break;
1413                 }
1414 #undef SET
1415                 static const struct { uint32_t xa9_type; char metadata[25]; } xa9typetoextrameta[] =
1416                 {
1417                     { ATOM_0xa9wrt, N_("Writer") },
1418                     { ATOM_0xa9com, N_("Composer") },
1419                     { ATOM_0xa9prd, N_("Producer") },
1420                     { ATOM_0xa9inf, N_("Information") },
1421                     { ATOM_0xa9dis, N_("Disclaimer") },
1422                     { ATOM_0xa9req, N_("Requirements") },
1423                     { ATOM_0xa9fmt, N_("Original Format") },
1424                     { ATOM_0xa9dsa, N_("Display Source As") },
1425                     { ATOM_0xa9hst, N_("Host Computer") },
1426                     { ATOM_0xa9prf, N_("Performers") },
1427                     { ATOM_0xa9ope, N_("Original Performer") },
1428                     { ATOM_0xa9src, N_("Providers Source Content") },
1429                     { ATOM_0xa9wrn, N_("Warning") },
1430                     { ATOM_0xa9swr, N_("Software") },
1431                     { ATOM_0xa9lyr, N_("Lyrics") },
1432                     { ATOM_0xa9mak, N_("Record Company") },
1433                     { ATOM_0xa9mod, N_("Model") },
1434                     { ATOM_0xa9PRD, N_("Product") },
1435                     { ATOM_0xa9grp, N_("Grouping") },
1436                     { ATOM_0xa9gen, N_("Genre") },
1437                     { ATOM_0xa9st3, N_("Sub-Title") },
1438                     { ATOM_0xa9arg, N_("Arranger") },
1439                     { ATOM_0xa9ard, N_("Art Director") },
1440                     { ATOM_0xa9cak, N_("Copyright Acknowledgement") },
1441                     { ATOM_0xa9con, N_("Conductor") },
1442                     { ATOM_0xa9des, N_("Song Description") },
1443                     { ATOM_0xa9lnt, N_("Liner Notes") },
1444                     { ATOM_0xa9phg, N_("Phonogram Rights") },
1445                     { ATOM_0xa9pub, N_("Publisher") },
1446                     { ATOM_0xa9sne, N_("Sound Engineer") },
1447                     { ATOM_0xa9sol, N_("Soloist") },
1448                     { ATOM_0xa9thx, N_("Thanks") },
1449                     { ATOM_0xa9xpd, N_("Executive Producer") },
1450                     { 0, "" },
1451                 };
1452                 for( unsigned i = 0; xa9typetoextrameta[i].xa9_type; i++ )
1453                 {
1454                     if( p_0xa9xxx->i_type == xa9typetoextrameta[i].xa9_type )
1455                     {
1456                         char *psz_utf = strdup( BOXDATA(p_0xa9xxx)->psz_text ? BOXDATA(p_0xa9xxx)->psz_text : "" );
1457                         if( psz_utf )
1458                         {
1459                              EnsureUTF8( psz_utf );
1460                              vlc_meta_AddExtra( p_meta, _(xa9typetoextrameta[i].metadata), psz_utf );
1461                              free( psz_utf );
1462                         }
1463                         break;
1464                     }
1465                 }
1466             }
1467             return VLC_SUCCESS;
1468         }
1469
1470         case DEMUX_GET_TITLE_INFO:
1471         {
1472             input_title_t ***ppp_title = (input_title_t***)va_arg( args, input_title_t*** );
1473             int *pi_int    = (int*)va_arg( args, int* );
1474             int *pi_title_offset = (int*)va_arg( args, int* );
1475             int *pi_seekpoint_offset = (int*)va_arg( args, int* );
1476
1477             if( !p_sys->p_title )
1478                 return VLC_EGENERIC;
1479
1480             *pi_int = 1;
1481             *ppp_title = malloc( sizeof( input_title_t*) );
1482             (*ppp_title)[0] = vlc_input_title_Duplicate( p_sys->p_title );
1483             *pi_title_offset = 0;
1484             *pi_seekpoint_offset = 0;
1485             return VLC_SUCCESS;
1486         }
1487         case DEMUX_SET_TITLE:
1488         {
1489             const int i_title = (int)va_arg( args, int );
1490             if( !p_sys->p_title || i_title != 0 )
1491                 return VLC_EGENERIC;
1492             return VLC_SUCCESS;
1493         }
1494         case DEMUX_SET_SEEKPOINT:
1495         {
1496             const int i_seekpoint = (int)va_arg( args, int );
1497             if( !p_sys->p_title )
1498                 return VLC_EGENERIC;
1499             return Seek( p_demux, p_sys->p_title->seekpoint[i_seekpoint]->i_time_offset );
1500         }
1501
1502         case DEMUX_SET_NEXT_DEMUX_TIME:
1503         case DEMUX_SET_GROUP:
1504         case DEMUX_HAS_UNSUPPORTED_META:
1505         case DEMUX_GET_PTS_DELAY:
1506         case DEMUX_CAN_RECORD:
1507             return VLC_EGENERIC;
1508
1509         default:
1510             msg_Warn( p_demux, "control query %u unimplemented", i_query );
1511             return VLC_EGENERIC;
1512     }
1513 }
1514
1515 /*****************************************************************************
1516  * Close: frees unused data
1517  *****************************************************************************/
1518 static void Close ( vlc_object_t * p_this )
1519 {
1520     demux_t *  p_demux = (demux_t *)p_this;
1521     demux_sys_t *p_sys = p_demux->p_sys;
1522     unsigned int i_track;
1523
1524     msg_Dbg( p_demux, "freeing all memory" );
1525
1526     MP4_BoxFree( p_demux->s, p_sys->p_root );
1527     for( i_track = 0; i_track < p_sys->i_tracks; i_track++ )
1528     {
1529         MP4_TrackDestroy(  &p_sys->track[i_track] );
1530     }
1531     FREENULL( p_sys->track );
1532
1533     if( p_sys->p_title )
1534         vlc_input_title_Delete( p_sys->p_title );
1535
1536     while( p_sys->moovfragment.p_next )
1537     {
1538         mp4_fragment_t *p_fragment = p_sys->moovfragment.p_next->p_next;
1539         free( p_sys->moovfragment.p_next );
1540         p_sys->moovfragment.p_next = p_fragment;
1541     }
1542
1543     free( p_sys );
1544 }
1545
1546
1547
1548 /****************************************************************************
1549  * Local functions, specific to vlc
1550  ****************************************************************************/
1551 /* Chapters */
1552 static void LoadChapterGpac( demux_t  *p_demux, MP4_Box_t *p_chpl )
1553 {
1554     demux_sys_t *p_sys = p_demux->p_sys;
1555     int i;
1556
1557     p_sys->p_title = vlc_input_title_New();
1558     for( i = 0; i < BOXDATA(p_chpl)->i_chapter; i++ )
1559     {
1560         seekpoint_t *s = vlc_seekpoint_New();
1561
1562         s->psz_name = strdup( BOXDATA(p_chpl)->chapter[i].psz_name );
1563         EnsureUTF8( s->psz_name );
1564         s->i_time_offset = BOXDATA(p_chpl)->chapter[i].i_start / 10;
1565         TAB_APPEND( p_sys->p_title->i_seekpoint, p_sys->p_title->seekpoint, s );
1566     }
1567 }
1568 static void LoadChapterApple( demux_t  *p_demux, mp4_track_t *tk )
1569 {
1570     demux_sys_t *p_sys = p_demux->p_sys;
1571
1572     for( tk->i_sample = 0; tk->i_sample < tk->i_sample_count; tk->i_sample++ )
1573     {
1574         const int64_t i_dts = MP4_TrackGetDTS( p_demux, tk );
1575         const int64_t i_pts_delta = MP4_TrackGetPTSDelta( p_demux, tk );
1576         uint32_t i_nb_samples = 0;
1577         const uint32_t i_size = MP4_TrackSampleSize( tk, &i_nb_samples );
1578
1579         if( i_size > 0 && !stream_Seek( p_demux->s, MP4_TrackGetPos( tk ) ) )
1580         {
1581             char p_buffer[256];
1582             const uint32_t i_read = stream_ReadU32( p_demux->s, p_buffer,
1583                                                     __MIN( sizeof(p_buffer), i_size ) );
1584             const uint32_t i_len = __MIN( GetWBE(p_buffer), i_read-2 );
1585
1586             if( i_len > 0 )
1587             {
1588                 seekpoint_t *s = vlc_seekpoint_New();
1589
1590                 s->psz_name = strndup( &p_buffer[2], i_len );
1591                 EnsureUTF8( s->psz_name );
1592
1593                 s->i_time_offset = i_dts + __MAX( i_pts_delta, 0 );
1594
1595                 if( !p_sys->p_title )
1596                     p_sys->p_title = vlc_input_title_New();
1597                 TAB_APPEND( p_sys->p_title->i_seekpoint, p_sys->p_title->seekpoint, s );
1598             }
1599         }
1600         if( tk->i_sample+1 >= tk->chunk[tk->i_chunk].i_sample_first +
1601                               tk->chunk[tk->i_chunk].i_sample_count )
1602             tk->i_chunk++;
1603     }
1604 }
1605 static void LoadChapter( demux_t  *p_demux )
1606 {
1607     demux_sys_t *p_sys = p_demux->p_sys;
1608     MP4_Box_t *p_chpl;
1609
1610     if( ( p_chpl = MP4_BoxGet( p_sys->p_root, "/moov/udta/chpl" ) ) && BOXDATA(p_chpl)->i_chapter > 0 )
1611     {
1612         LoadChapterGpac( p_demux, p_chpl );
1613     }
1614     else if( p_sys->p_tref_chap )
1615     {
1616         MP4_Box_data_tref_generic_t *p_chap = p_sys->p_tref_chap->data.p_tref_generic;
1617         unsigned int i, j;
1618
1619         /* Load the first subtitle track like quicktime */
1620         for( i = 0; i < p_chap->i_entry_count; i++ )
1621         {
1622             for( j = 0; j < p_sys->i_tracks; j++ )
1623             {
1624                 mp4_track_t *tk = &p_sys->track[j];
1625                 if( tk->b_ok && tk->i_track_ID == p_chap->i_track_ID[i] &&
1626                     tk->fmt.i_cat == SPU_ES && tk->fmt.i_codec == VLC_CODEC_SUBT )
1627                     break;
1628             }
1629             if( j < p_sys->i_tracks )
1630             {
1631                 LoadChapterApple( p_demux, &p_sys->track[j] );
1632                 break;
1633             }
1634         }
1635     }
1636
1637     /* Add duration if titles are enabled */
1638     if( p_sys->p_title )
1639     {
1640         p_sys->p_title->i_length = CLOCK_FREQ *
1641                        (uint64_t)p_sys->i_overall_duration / (uint64_t)p_sys->i_timescale;
1642     }
1643 }
1644
1645 /* now create basic chunk data, the rest will be filled by MP4_CreateSamplesIndex */
1646 static int TrackCreateChunksIndex( demux_t *p_demux,
1647                                    mp4_track_t *p_demux_track )
1648 {
1649     demux_sys_t *p_sys = p_demux->p_sys;
1650
1651     MP4_Box_t *p_co64; /* give offset for each chunk, same for stco and co64 */
1652     MP4_Box_t *p_stsc;
1653
1654     unsigned int i_chunk;
1655     unsigned int i_index, i_last;
1656
1657     if( ( !(p_co64 = MP4_BoxGet( p_demux_track->p_stbl, "stco" ) )&&
1658           !(p_co64 = MP4_BoxGet( p_demux_track->p_stbl, "co64" ) ) )||
1659         ( !(p_stsc = MP4_BoxGet( p_demux_track->p_stbl, "stsc" ) ) ))
1660     {
1661         return( VLC_EGENERIC );
1662     }
1663
1664     p_demux_track->i_chunk_count = BOXDATA(p_co64)->i_entry_count;
1665     if( !p_demux_track->i_chunk_count )
1666     {
1667         msg_Warn( p_demux, "no chunk defined" );
1668     }
1669     p_demux_track->chunk = calloc( p_demux_track->i_chunk_count,
1670                                    sizeof( mp4_chunk_t ) );
1671     if( p_demux_track->chunk == NULL )
1672     {
1673         return VLC_ENOMEM;
1674     }
1675
1676     /* first we read chunk offset */
1677     for( i_chunk = 0; i_chunk < p_demux_track->i_chunk_count; i_chunk++ )
1678     {
1679         mp4_chunk_t *ck = &p_demux_track->chunk[i_chunk];
1680
1681         ck->i_offset = BOXDATA(p_co64)->i_chunk_offset[i_chunk];
1682
1683         ck->i_first_dts = 0;
1684         ck->p_sample_count_dts = NULL;
1685         ck->p_sample_delta_dts = NULL;
1686         ck->p_sample_count_pts = NULL;
1687         ck->p_sample_offset_pts = NULL;
1688     }
1689
1690     /* now we read index for SampleEntry( soun vide mp4a mp4v ...)
1691         to be used for the sample XXX begin to 1
1692         We construct it begining at the end */
1693     i_last = p_demux_track->i_chunk_count; /* last chunk proceded */
1694     i_index = BOXDATA(p_stsc)->i_entry_count;
1695
1696     while( i_index-- > 0 )
1697     {
1698         for( i_chunk = BOXDATA(p_stsc)->i_first_chunk[i_index] - 1;
1699              i_chunk < i_last; i_chunk++ )
1700         {
1701             if( i_chunk >= p_demux_track->i_chunk_count )
1702             {
1703                 msg_Warn( p_demux, "corrupted chunk table" );
1704                 return VLC_EGENERIC;
1705             }
1706
1707             p_demux_track->chunk[i_chunk].i_sample_description_index =
1708                     BOXDATA(p_stsc)->i_sample_description_index[i_index];
1709             p_demux_track->chunk[i_chunk].i_sample_count =
1710                     BOXDATA(p_stsc)->i_samples_per_chunk[i_index];
1711         }
1712         i_last = BOXDATA(p_stsc)->i_first_chunk[i_index] - 1;
1713     }
1714
1715     p_demux_track->chunk[0].i_sample_first = 0;
1716     for( i_chunk = 1; i_chunk < p_demux_track->i_chunk_count; i_chunk++ )
1717     {
1718         p_demux_track->chunk[i_chunk].i_sample_first =
1719             p_demux_track->chunk[i_chunk-1].i_sample_first +
1720                 p_demux_track->chunk[i_chunk-1].i_sample_count;
1721     }
1722
1723     msg_Dbg( p_demux, "track[Id 0x%x] read %d chunk",
1724              p_demux_track->i_track_ID, p_demux_track->i_chunk_count );
1725
1726     if ( p_demux_track->i_chunk_count && (
1727              p_sys->moovfragment.i_chunk_range_min_offset == 0 ||
1728              p_sys->moovfragment.i_chunk_range_min_offset > p_demux_track->chunk[0].i_offset
1729              ) )
1730         p_sys->moovfragment.i_chunk_range_min_offset = p_demux_track->chunk[0].i_offset;
1731
1732     return VLC_SUCCESS;
1733 }
1734
1735 static int xTTS_CountEntries( demux_t *p_demux, uint32_t *pi_entry /* out */,
1736                               const uint32_t i_index,
1737                               uint32_t i_index_samples_left,
1738                               uint32_t i_sample_count,
1739                               const uint32_t *pi_index_sample_count,
1740                               const uint32_t i_table_count )
1741 {
1742     uint32_t i_array_offset;
1743     while( i_sample_count > 0 )
1744     {
1745         if ( likely((UINT32_MAX - i_index) >= *pi_entry) )
1746             i_array_offset = i_index + *pi_entry;
1747         else
1748             return VLC_EGENERIC;
1749
1750         if ( i_array_offset >= i_table_count )
1751         {
1752             msg_Err( p_demux, "invalid index counting total samples %u %u", i_array_offset,  i_table_count );
1753             return VLC_EGENERIC;
1754         }
1755
1756         if ( i_index_samples_left )
1757         {
1758             if ( i_index_samples_left > i_sample_count )
1759             {
1760                 i_index_samples_left -= i_sample_count;
1761                 i_sample_count = 0;
1762                 *pi_entry +=1; /* No samples left, go copy */
1763                 break;
1764             }
1765             else
1766             {
1767                 i_sample_count -= i_index_samples_left;
1768                 i_index_samples_left = 0;
1769                 *pi_entry += 1;
1770                 continue;
1771             }
1772         }
1773         else
1774         {
1775             i_sample_count -= __MIN( i_sample_count, pi_index_sample_count[i_array_offset] );
1776             *pi_entry += 1;
1777         }
1778     }
1779
1780     return VLC_SUCCESS;
1781 }
1782
1783 static int TrackCreateSamplesIndex( demux_t *p_demux,
1784                                     mp4_track_t *p_demux_track )
1785 {
1786     demux_sys_t *p_sys = p_demux->p_sys;
1787
1788     MP4_Box_t *p_box;
1789     MP4_Box_data_stsz_t *stsz;
1790     /* TODO use also stss and stsh table for seeking */
1791     /* FIXME use edit table */
1792
1793     /* Find stsz
1794      *  Gives the sample size for each samples. There is also a stz2 table
1795      *  (compressed form) that we need to implement TODO */
1796     p_box = MP4_BoxGet( p_demux_track->p_stbl, "stsz" );
1797     if( !p_box )
1798     {
1799         /* FIXME and stz2 */
1800         msg_Warn( p_demux, "cannot find STSZ box" );
1801         return VLC_EGENERIC;
1802     }
1803     stsz = p_box->data.p_stsz;
1804
1805     /* Use stsz table to create a sample number -> sample size table */
1806     p_demux_track->i_sample_count = stsz->i_sample_count;
1807     if( stsz->i_sample_size )
1808     {
1809         /* 1: all sample have the same size, so no need to construct a table */
1810         p_demux_track->i_sample_size = stsz->i_sample_size;
1811         p_demux_track->p_sample_size = NULL;
1812     }
1813     else
1814     {
1815         /* 2: each sample can have a different size */
1816         p_demux_track->i_sample_size = 0;
1817         p_demux_track->p_sample_size =
1818             calloc( p_demux_track->i_sample_count, sizeof( uint32_t ) );
1819         if( p_demux_track->p_sample_size == NULL )
1820             return VLC_ENOMEM;
1821
1822         for( uint32_t i_sample = 0; i_sample < p_demux_track->i_sample_count; i_sample++ )
1823         {
1824             p_demux_track->p_sample_size[i_sample] =
1825                     stsz->i_entry_size[i_sample];
1826         }
1827     }
1828
1829     if ( p_demux_track->i_chunk_count )
1830     {
1831         mp4_chunk_t *lastchunk = &p_demux_track->chunk[p_demux_track->i_chunk_count - 1];
1832         uint64_t i_total_size = lastchunk->i_offset;
1833         for( uint32_t i=0; i<lastchunk->i_sample_count; i++)
1834         {
1835             if( p_demux_track->i_sample_size == 0 )
1836                 i_total_size += stsz->i_entry_size[i];
1837             else
1838                 i_total_size += p_demux_track->i_sample_size;
1839         }
1840
1841         if ( i_total_size > p_sys->moovfragment.i_chunk_range_max_offset )
1842             p_sys->moovfragment.i_chunk_range_max_offset = i_total_size;
1843     }
1844
1845     /* Use stts table to create a sample number -> dts table.
1846      * XXX: if we don't want to waste too much memory, we can't expand
1847      *  the box! so each chunk will contain an "extract" of this table
1848      *  for fast research (problem with raw stream where a sample is sometime
1849      *  just channels*bits_per_sample/8 */
1850
1851      /* FIXME: refactor STTS & CTTS, STTS having now only few extra lines and
1852       *        differing in 2/2 fields and 1 signedness */
1853
1854     mtime_t i_next_dts = 0;
1855     /* Find stts
1856      *  Gives mapping between sample and decoding time
1857      */
1858     p_box = MP4_BoxGet( p_demux_track->p_stbl, "stts" );
1859     if( !p_box )
1860     {
1861         msg_Warn( p_demux, "cannot find STTS box" );
1862         return VLC_EGENERIC;
1863     }
1864     else
1865     {
1866         MP4_Box_data_stts_t *stts = p_box->data.p_stts;
1867
1868         msg_Warn( p_demux, "STTS table of %"PRIu32" entries", stts->i_entry_count );
1869
1870         /* Create sample -> dts table per chunk */
1871         uint32_t i_index = 0;
1872         uint32_t i_current_index_samples_left = 0;
1873
1874         for( uint32_t i_chunk = 0; i_chunk < p_demux_track->i_chunk_count; i_chunk++ )
1875         {
1876             mp4_chunk_t *ck = &p_demux_track->chunk[i_chunk];
1877             uint32_t i_entry, i_sample_count;
1878
1879             /* save first dts */
1880             ck->i_first_dts = i_next_dts;
1881             ck->i_last_dts  = i_next_dts;
1882
1883             /* count how many entries are needed for this chunk
1884              * for p_sample_delta_dts and p_sample_count_dts */
1885             i_entry = 0;
1886
1887             int i_ret = xTTS_CountEntries( p_demux, &i_entry, i_index,
1888                                            i_current_index_samples_left,
1889                                            ck->i_sample_count,
1890                                            stts->pi_sample_count,
1891                                            stts->i_entry_count );
1892             if ( i_ret != VLC_SUCCESS )
1893                 return i_ret;
1894
1895             /* allocate them */
1896             ck->p_sample_count_dts = calloc( i_entry, sizeof( uint32_t ) );
1897             ck->p_sample_delta_dts = calloc( i_entry, sizeof( uint32_t ) );
1898             if( !ck->p_sample_count_dts || !ck->p_sample_delta_dts )
1899             {
1900                 msg_Err( p_demux, "can't allocate memory for i_entry=%"PRIu32, i_entry );
1901                 return VLC_ENOMEM;
1902             }
1903
1904             /* now copy */
1905             i_sample_count = ck->i_sample_count;
1906
1907             for( uint32_t i = 0; i < i_entry; i++ )
1908             {
1909                 if ( i_current_index_samples_left )
1910                 {
1911                     if ( i_current_index_samples_left > i_sample_count )
1912                     {
1913                         if ( i_sample_count ) ck->i_last_dts = i_next_dts;
1914                         ck->p_sample_count_dts[i] = i_sample_count;
1915                         ck->p_sample_delta_dts[i] = stts->pi_sample_delta[i_index];
1916                         i_next_dts += ck->p_sample_count_dts[i] * stts->pi_sample_delta[i_index];
1917                         i_current_index_samples_left -= i_sample_count;
1918                         i_sample_count = 0;
1919                         assert( i == i_entry - 1 );
1920                         break;
1921                     }
1922                     else
1923                     {
1924                         if ( i_current_index_samples_left ) ck->i_last_dts = i_next_dts;
1925                         ck->p_sample_count_dts[i] = i_current_index_samples_left;
1926                         ck->p_sample_delta_dts[i] = stts->pi_sample_delta[i_index];
1927                         i_next_dts += ck->p_sample_count_dts[i] * stts->pi_sample_delta[i_index];
1928                         i_sample_count -= i_current_index_samples_left;
1929                         i_current_index_samples_left = 0;
1930                         i_index++;
1931                     }
1932                 }
1933                 else
1934                 {
1935                     if ( stts->pi_sample_count[i_index] > i_sample_count )
1936                     {
1937                         if ( i_sample_count ) ck->i_last_dts = i_next_dts;
1938                         ck->p_sample_count_dts[i] = i_sample_count;
1939                         ck->p_sample_delta_dts[i] = stts->pi_sample_delta[i_index];
1940                         i_next_dts += ck->p_sample_count_dts[i] * stts->pi_sample_delta[i_index];
1941                         i_current_index_samples_left = stts->pi_sample_count[i_index] - i_sample_count;
1942                         i_sample_count = 0;
1943                         assert( i == i_entry - 1 );
1944                         // keep building from same index
1945                     }
1946                     else
1947                     {
1948                         if ( stts->pi_sample_count[i_index] ) ck->i_last_dts = i_next_dts;
1949                         ck->p_sample_count_dts[i] = stts->pi_sample_count[i_index];
1950                         ck->p_sample_delta_dts[i] = stts->pi_sample_delta[i_index];
1951                         i_next_dts += ck->p_sample_count_dts[i] * stts->pi_sample_delta[i_index];
1952                         i_sample_count -= stts->pi_sample_count[i_index];
1953                         i_index++;
1954                     }
1955                 }
1956
1957             }
1958         }
1959     }
1960
1961
1962     /* Find ctts
1963      *  Gives the delta between decoding time (dts) and composition table (pts)
1964      */
1965     p_box = MP4_BoxGet( p_demux_track->p_stbl, "ctts" );
1966     if( p_box )
1967     {
1968         MP4_Box_data_ctts_t *ctts = p_box->data.p_ctts;
1969
1970         msg_Warn( p_demux, "CTTS table of %"PRIu32" entries", ctts->i_entry_count );
1971
1972         /* Create pts-dts table per chunk */
1973         uint32_t i_index = 0;
1974         uint32_t i_current_index_samples_left = 0;
1975
1976         for( uint32_t i_chunk = 0; i_chunk < p_demux_track->i_chunk_count; i_chunk++ )
1977         {
1978             mp4_chunk_t *ck = &p_demux_track->chunk[i_chunk];
1979             uint32_t i_entry, i_sample_count;
1980
1981             /* count how many entries are needed for this chunk
1982              * for p_sample_offset_pts and p_sample_count_pts */
1983             i_entry = 0;
1984             int i_ret = xTTS_CountEntries( p_demux, &i_entry, i_index,
1985                                            i_current_index_samples_left,
1986                                            ck->i_sample_count,
1987                                            ctts->pi_sample_count,
1988                                            ctts->i_entry_count );
1989             if ( i_ret != VLC_SUCCESS )
1990                 return i_ret;
1991
1992             /* allocate them */
1993             ck->p_sample_count_pts = calloc( i_entry, sizeof( uint32_t ) );
1994             ck->p_sample_offset_pts = calloc( i_entry, sizeof( int32_t ) );
1995             if( !ck->p_sample_count_pts || !ck->p_sample_offset_pts )
1996             {
1997                 msg_Err( p_demux, "can't allocate memory for i_entry=%"PRIu32, i_entry );
1998                 return VLC_ENOMEM;
1999             }
2000
2001             /* now copy */
2002             i_sample_count = ck->i_sample_count;
2003
2004             for( uint32_t i = 0; i < i_entry; i++ )
2005             {
2006                 if ( i_current_index_samples_left )
2007                 {
2008                     if ( i_current_index_samples_left > i_sample_count )
2009                     {
2010                         ck->p_sample_count_pts[i] = i_sample_count;
2011                         ck->p_sample_offset_pts[i] = ctts->pi_sample_offset[i_index];
2012                         i_current_index_samples_left -= i_sample_count;
2013                         i_sample_count = 0;
2014                         assert( i == i_entry - 1 );
2015                         break;
2016                     }
2017                     else
2018                     {
2019                         ck->p_sample_count_pts[i] = i_current_index_samples_left;
2020                         ck->p_sample_offset_pts[i] = ctts->pi_sample_offset[i_index];
2021                         i_sample_count -= i_current_index_samples_left;
2022                         i_current_index_samples_left = 0;
2023                         i_index++;
2024                     }
2025                 }
2026                 else
2027                 {
2028                     if ( ctts->pi_sample_count[i_index] > i_sample_count )
2029                     {
2030                         ck->p_sample_count_pts[i] = i_sample_count;
2031                         ck->p_sample_offset_pts[i] = ctts->pi_sample_offset[i_index];
2032                         i_current_index_samples_left = ctts->pi_sample_count[i_index] - i_sample_count;
2033                         i_sample_count = 0;
2034                         assert( i == i_entry - 1 );
2035                         // keep building from same index
2036                     }
2037                     else
2038                     {
2039                         ck->p_sample_count_pts[i] = ctts->pi_sample_count[i_index];
2040                         ck->p_sample_offset_pts[i] = ctts->pi_sample_offset[i_index];
2041                         i_sample_count -= ctts->pi_sample_count[i_index];
2042                         i_index++;
2043                     }
2044                 }
2045
2046
2047             }
2048         }
2049     }
2050
2051     msg_Dbg( p_demux, "track[Id 0x%x] read %"PRIu32" samples length:%"PRId64"s",
2052              p_demux_track->i_track_ID, p_demux_track->i_sample_count,
2053              i_next_dts / p_demux_track->i_timescale );
2054
2055     return VLC_SUCCESS;
2056 }
2057
2058
2059 /**
2060  * It computes the sample rate for a video track using the given sample
2061  * description index
2062  */
2063 static void TrackGetESSampleRate( demux_t *p_demux,
2064                                   unsigned *pi_num, unsigned *pi_den,
2065                                   const mp4_track_t *p_track,
2066                                   unsigned i_sd_index,
2067                                   unsigned i_chunk )
2068 {
2069     *pi_num = 0;
2070     *pi_den = 0;
2071
2072     MP4_Box_t *p_trak = MP4_GetTrakByTrackID( MP4_BoxGet( p_demux->p_sys->p_root, "/moov" ),
2073                                               p_track->i_track_ID );
2074     MP4_Box_t *p_mdhd = MP4_BoxGet( p_trak, "mdia/mdhd" );
2075     if ( p_mdhd )
2076     {
2077         vlc_ureduce( pi_num, pi_den,
2078                      (uint64_t) BOXDATA(p_mdhd)->i_timescale * p_track->i_sample_count,
2079                      (uint64_t) BOXDATA(p_mdhd)->i_duration,
2080                      UINT16_MAX );
2081         return;
2082     }
2083
2084     if( p_track->i_chunk_count <= 0 )
2085         return;
2086
2087     /* */
2088     const mp4_chunk_t *p_chunk = &p_track->chunk[i_chunk];
2089     while( p_chunk > &p_track->chunk[0] &&
2090            p_chunk[-1].i_sample_description_index == i_sd_index )
2091     {
2092         p_chunk--;
2093     }
2094
2095     uint64_t i_sample = 0;
2096     uint64_t i_first_dts = p_chunk->i_first_dts;
2097     uint64_t i_last_dts;
2098     do
2099     {
2100         i_sample += p_chunk->i_sample_count;
2101         i_last_dts = p_chunk->i_last_dts;
2102         p_chunk++;
2103     }
2104     while( p_chunk < &p_track->chunk[p_track->i_chunk_count] &&
2105            p_chunk->i_sample_description_index == i_sd_index );
2106
2107     if( i_sample > 1 && i_first_dts < i_last_dts )
2108         vlc_ureduce( pi_num, pi_den,
2109                      ( i_sample - 1) *  p_track->i_timescale,
2110                      i_last_dts - i_first_dts,
2111                      UINT16_MAX);
2112 }
2113
2114 /*
2115  * TrackCreateES:
2116  * Create ES and PES to init decoder if needed, for a track starting at i_chunk
2117  */
2118 static int TrackCreateES( demux_t *p_demux, mp4_track_t *p_track,
2119                           unsigned int i_chunk, es_out_id_t **pp_es )
2120 {
2121     demux_sys_t *p_sys = p_demux->p_sys;
2122     unsigned int i_sample_description_index;
2123
2124     if( p_sys->b_fragmented )
2125         i_sample_description_index = 1; /* XXX */
2126     else
2127         i_sample_description_index =
2128                 p_track->chunk[i_chunk].i_sample_description_index;
2129
2130     MP4_Box_t   *p_sample;
2131     MP4_Box_t   *p_esds;
2132     MP4_Box_t   *p_frma;
2133     MP4_Box_t   *p_enda;
2134     MP4_Box_t   *p_pasp;
2135
2136     if( pp_es )
2137         *pp_es = NULL;
2138
2139     if( !i_sample_description_index )
2140     {
2141         msg_Warn( p_demux, "invalid SampleEntry index (track[Id 0x%x])",
2142                   p_track->i_track_ID );
2143         return VLC_EGENERIC;
2144     }
2145
2146     p_sample = MP4_BoxGet(  p_track->p_stsd, "[%d]",
2147                             i_sample_description_index - 1 );
2148
2149     if( !p_sample ||
2150         ( !p_sample->data.p_payload && p_track->fmt.i_cat != SPU_ES ) )
2151     {
2152         msg_Warn( p_demux, "cannot find SampleEntry (track[Id 0x%x])",
2153                   p_track->i_track_ID );
2154         return VLC_EGENERIC;
2155     }
2156
2157     p_track->p_sample = p_sample;
2158
2159     if( ( p_frma = MP4_BoxGet( p_track->p_sample, "sinf/frma" ) ) )
2160     {
2161         msg_Warn( p_demux, "Original Format Box: %4.4s", (char *)&p_frma->data.p_frma->i_type );
2162
2163         p_sample->i_type = p_frma->data.p_frma->i_type;
2164     }
2165
2166     p_enda = MP4_BoxGet( p_sample, "wave/enda" );
2167     if( !p_enda )
2168         p_enda = MP4_BoxGet( p_sample, "enda" );
2169
2170     p_pasp = MP4_BoxGet( p_sample, "pasp" );
2171
2172     /* */
2173     switch( p_track->fmt.i_cat )
2174     {
2175     case VIDEO_ES:
2176         p_track->fmt.video.i_width = p_sample->data.p_sample_vide->i_width;
2177         p_track->fmt.video.i_height = p_sample->data.p_sample_vide->i_height;
2178         p_track->fmt.video.i_bits_per_pixel =
2179             p_sample->data.p_sample_vide->i_depth;
2180
2181         /* fall on display size */
2182         if( p_track->fmt.video.i_width <= 0 )
2183             p_track->fmt.video.i_width = p_track->i_width;
2184         if( p_track->fmt.video.i_height <= 0 )
2185             p_track->fmt.video.i_height = p_track->i_height;
2186
2187         /* Find out apect ratio from display size */
2188         if( p_track->i_width > 0 && p_track->i_height > 0 &&
2189             /* Work-around buggy muxed files */
2190             p_sample->data.p_sample_vide->i_width != p_track->i_width )
2191         {
2192             p_track->fmt.video.i_sar_num = p_track->i_width  * p_track->fmt.video.i_height;
2193             p_track->fmt.video.i_sar_den = p_track->i_height * p_track->fmt.video.i_width;
2194         }
2195         if( p_pasp && p_pasp->data.p_pasp->i_horizontal_spacing > 0 &&
2196                       p_pasp->data.p_pasp->i_vertical_spacing > 0 )
2197         {
2198             p_track->fmt.video.i_sar_num = p_pasp->data.p_pasp->i_horizontal_spacing;
2199             p_track->fmt.video.i_sar_den = p_pasp->data.p_pasp->i_vertical_spacing;
2200         }
2201
2202         /* Support for cropping (eg. in H263 files) */
2203         p_track->fmt.video.i_visible_width = p_track->fmt.video.i_width;
2204         p_track->fmt.video.i_visible_height = p_track->fmt.video.i_height;
2205
2206         /* Frame rate */
2207         TrackGetESSampleRate( p_demux,
2208                               &p_track->fmt.video.i_frame_rate,
2209                               &p_track->fmt.video.i_frame_rate_base,
2210                               p_track, i_sample_description_index, i_chunk );
2211
2212         p_demux->p_sys->f_fps = (float)p_track->fmt.video.i_frame_rate /
2213                                 (float)p_track->fmt.video.i_frame_rate_base;
2214
2215         /* Rotation */
2216         switch( (int)p_track->f_rotation ) {
2217             case 90:
2218                 p_track->fmt.video.orientation = ORIENT_ROTATED_90;
2219                 break;
2220             case 180:
2221                 p_track->fmt.video.orientation = ORIENT_ROTATED_180;
2222                 break;
2223             case 270:
2224                 p_track->fmt.video.orientation = ORIENT_ROTATED_270;
2225                 break;
2226         }
2227
2228         break;
2229
2230     case AUDIO_ES:
2231         p_track->fmt.audio.i_channels =
2232             p_sample->data.p_sample_soun->i_channelcount;
2233         p_track->fmt.audio.i_rate =
2234             p_sample->data.p_sample_soun->i_sampleratehi;
2235         p_track->fmt.i_bitrate = p_sample->data.p_sample_soun->i_channelcount *
2236             p_sample->data.p_sample_soun->i_sampleratehi *
2237                 p_sample->data.p_sample_soun->i_samplesize;
2238         p_track->fmt.audio.i_bitspersample =
2239             p_sample->data.p_sample_soun->i_samplesize;
2240
2241         if( ( p_track->i_sample_size == 1 || p_track->i_sample_size == 2 ) )
2242         {
2243             MP4_Box_data_sample_soun_t *p_soun;
2244             p_soun = p_sample->data.p_sample_soun;
2245
2246             if( p_soun->i_qt_version == 0 )
2247             {
2248                 switch( p_sample->i_type )
2249                 {
2250                     case VLC_CODEC_ADPCM_IMA_QT:
2251                         p_soun->i_qt_version = 1;
2252                         p_soun->i_sample_per_packet = 64;
2253                         p_soun->i_bytes_per_packet  = 34;
2254                         p_soun->i_bytes_per_frame   = 34 * p_soun->i_channelcount;
2255                         p_soun->i_bytes_per_sample  = 2;
2256                         break;
2257                     case VLC_CODEC_MACE3:
2258                         p_soun->i_qt_version = 1;
2259                         p_soun->i_sample_per_packet = 6;
2260                         p_soun->i_bytes_per_packet  = 2;
2261                         p_soun->i_bytes_per_frame   = 2 * p_soun->i_channelcount;
2262                         p_soun->i_bytes_per_sample  = 2;
2263                         break;
2264                     case VLC_CODEC_MACE6:
2265                         p_soun->i_qt_version = 1;
2266                         p_soun->i_sample_per_packet = 12;
2267                         p_soun->i_bytes_per_packet  = 2;
2268                         p_soun->i_bytes_per_frame   = 2 * p_soun->i_channelcount;
2269                         p_soun->i_bytes_per_sample  = 2;
2270                         break;
2271                     case VLC_CODEC_ALAW:
2272                     case VLC_FOURCC( 'u', 'l', 'a', 'w' ):
2273                         p_soun->i_samplesize = 8;
2274                         p_track->i_sample_size = p_soun->i_channelcount;
2275                         break;
2276                     case VLC_FOURCC( 'N', 'O', 'N', 'E' ):
2277                     case VLC_FOURCC( 'r', 'a', 'w', ' ' ):
2278                     case VLC_FOURCC( 't', 'w', 'o', 's' ):
2279                     case VLC_FOURCC( 's', 'o', 'w', 't' ):
2280                         /* What would be the fun if you could trust the .mov */
2281                         p_track->i_sample_size = ((p_soun->i_samplesize+7)/8) * p_soun->i_channelcount;
2282                         break;
2283                     default:
2284                         break;
2285                 }
2286
2287             }
2288             else if( p_soun->i_qt_version == 1 && p_soun->i_sample_per_packet <= 0 )
2289             {
2290                 p_soun->i_qt_version = 0;
2291             }
2292         }
2293         else if( p_sample->data.p_sample_soun->i_qt_version == 1 )
2294         {
2295             MP4_Box_data_sample_soun_t *p_soun = p_sample->data.p_sample_soun;
2296
2297             switch( p_sample->i_type )
2298             {
2299                 case( VLC_FOURCC( '.', 'm', 'p', '3' ) ):
2300                 case( VLC_FOURCC( 'm', 's', 0x00, 0x55 ) ):
2301                     {
2302                         if( p_track->i_sample_size > 1 )
2303                             p_soun->i_qt_version = 0;
2304                         break;
2305                     }
2306                 case( VLC_FOURCC( 'a', 'c', '-', '3' ) ):
2307                 case( VLC_FOURCC( 'e', 'c', '-', '3' ) ):
2308                 case( VLC_FOURCC( 'm', 's', 0x20, 0x00 ) ):
2309                     p_soun->i_qt_version = 0;
2310                     break;
2311                 default:
2312                     break;
2313             }
2314         }
2315
2316         if( p_track->i_sample_size != 0 &&
2317                 p_sample->data.p_sample_soun->i_qt_version == 1 &&
2318                 p_sample->data.p_sample_soun->i_sample_per_packet <= 0 )
2319         {
2320             msg_Err( p_demux, "Invalid sample per packet value for qt_version 1. Broken muxer!" );
2321             p_sample->data.p_sample_soun->i_qt_version = 0;
2322         }
2323         break;
2324
2325     default:
2326         break;
2327     }
2328
2329
2330     /* It's a little ugly but .. there are special cases */
2331     switch( p_sample->i_type )
2332     {
2333         case( VLC_FOURCC( '.', 'm', 'p', '3' ) ):
2334         case( VLC_FOURCC( 'm', 's', 0x00, 0x55 ) ):
2335         {
2336             p_track->fmt.i_codec = VLC_CODEC_MPGA;
2337             break;
2338         }
2339         case( VLC_FOURCC( 'a', 'c', '-', '3' ) ):
2340         {
2341             MP4_Box_t *p_dac3_box = MP4_BoxGet(  p_sample, "dac3", 0 );
2342
2343             p_track->fmt.i_codec = VLC_CODEC_A52;
2344             if( p_dac3_box )
2345             {
2346                 static const int pi_bitrate[] = {
2347                      32,  40,  48,  56,
2348                      64,  80,  96, 112,
2349                     128, 160, 192, 224,
2350                     256, 320, 384, 448,
2351                     512, 576, 640,
2352                 };
2353                 MP4_Box_data_dac3_t *p_dac3 = p_dac3_box->data.p_dac3;
2354                 p_track->fmt.audio.i_channels = 0;
2355                 p_track->fmt.i_bitrate = 0;
2356                 if( p_dac3->i_bitrate_code < sizeof(pi_bitrate)/sizeof(*pi_bitrate) )
2357                     p_track->fmt.i_bitrate = pi_bitrate[p_dac3->i_bitrate_code] * 1000;
2358                 p_track->fmt.audio.i_bitspersample = 0;
2359             }
2360             break;
2361         }
2362         case( VLC_FOURCC( 'e', 'c', '-', '3' ) ):
2363         {
2364             p_track->fmt.i_codec = VLC_CODEC_EAC3;
2365             break;
2366         }
2367
2368         case( VLC_FOURCC( 'r', 'a', 'w', ' ' ) ):
2369         case( VLC_FOURCC( 'N', 'O', 'N', 'E' ) ):
2370         {
2371             MP4_Box_data_sample_soun_t *p_soun = p_sample->data.p_sample_soun;
2372
2373             if(p_soun && (p_soun->i_samplesize+7)/8 == 1 )
2374                 p_track->fmt.i_codec = VLC_CODEC_U8;
2375             else
2376                 p_track->fmt.i_codec = VLC_FOURCC( 't', 'w', 'o', 's' );
2377
2378             /* Buggy files workaround */
2379             if( p_sample->data.p_sample_soun && (p_track->i_timescale !=
2380                 p_sample->data.p_sample_soun->i_sampleratehi) )
2381             {
2382                 MP4_Box_data_sample_soun_t *p_soun =
2383                     p_sample->data.p_sample_soun;
2384
2385                 msg_Warn( p_demux, "i_timescale (%"PRId32") != i_sampleratehi "
2386                           "(%u), making both equal (report any problem).",
2387                           p_track->i_timescale, p_soun->i_sampleratehi );
2388
2389                 if( p_soun->i_sampleratehi != 0 )
2390                     p_track->i_timescale = p_soun->i_sampleratehi;
2391                 else
2392                     p_soun->i_sampleratehi = p_track->i_timescale;
2393             }
2394             break;
2395         }
2396
2397         case( VLC_FOURCC( 's', '2', '6', '3' ) ):
2398             p_track->fmt.i_codec = VLC_CODEC_H263;
2399             break;
2400
2401         case( VLC_FOURCC( 't', 'e', 'x', 't' ) ):
2402         case( VLC_FOURCC( 't', 'x', '3', 'g' ) ):
2403         {
2404             p_track->fmt.i_codec = VLC_CODEC_TX3G;
2405             MP4_Box_data_sample_text_t *p_text = p_sample->data.p_sample_text;
2406             if ( p_text )
2407             {
2408                 text_style_t *p_style = text_style_New();
2409                 if ( p_style )
2410                 {
2411                     if ( p_text->i_font_size ) /* !WARN: % in absolute storage */
2412                         p_style->i_font_size = p_text->i_font_size;
2413                     if ( p_text->i_font_color )
2414                     {
2415                         p_style->i_font_color = p_text->i_font_color >> 8;
2416                         p_style->i_font_alpha = p_text->i_font_color & 0xFF;
2417                     }
2418                     if ( p_text->i_background_color[3] >> 8 )
2419                     {
2420                         p_style->i_background_color = p_text->i_background_color[0] >> 8;
2421                         p_style->i_background_color |= p_text->i_background_color[1] >> 8;
2422                         p_style->i_background_color |= p_text->i_background_color[2] >> 8;
2423                         p_style->i_background_alpha = p_text->i_background_color[3] >> 8;
2424                     }
2425                 }
2426                 p_track->fmt.subs.p_style = p_style;
2427             }
2428             /* FIXME UTF-8 doesn't work here ? */
2429             if( p_track->b_mac_encoding )
2430                 p_track->fmt.subs.psz_encoding = strdup( "MAC" );
2431             else
2432                 p_track->fmt.subs.psz_encoding = strdup( "UTF-8" );
2433             break;
2434         }
2435         case VLC_FOURCC('y','v','1','2'):
2436             p_track->fmt.i_codec = VLC_CODEC_YV12;
2437             break;
2438         case VLC_FOURCC('y','u','v','2'):
2439             p_track->fmt.i_codec = VLC_FOURCC('Y','U','Y','2');
2440             break;
2441
2442         case VLC_FOURCC('i','n','2','4'):
2443             p_track->fmt.i_codec = p_enda && BOXDATA(p_enda)->i_little_endian == 1 ?
2444                                     VLC_FOURCC('4','2','n','i') : VLC_FOURCC('i','n','2','4');
2445             break;
2446         case VLC_FOURCC('i','n','3','2'):
2447             p_track->fmt.i_codec = p_enda && BOXDATA(p_enda)->i_little_endian == 1 ?
2448                                     VLC_CODEC_S32L : VLC_CODEC_S32B;
2449             break;
2450         case VLC_FOURCC('f','l','3','2'):
2451             p_track->fmt.i_codec = p_enda && BOXDATA(p_enda)->i_little_endian == 1 ?
2452                                     VLC_CODEC_F32L : VLC_CODEC_F32B;
2453             break;
2454         case VLC_FOURCC('f','l','6','4'):
2455             p_track->fmt.i_codec = p_enda && BOXDATA(p_enda)->i_little_endian == 1 ?
2456                                     VLC_CODEC_F64L : VLC_CODEC_F64B;
2457             break;
2458         case VLC_CODEC_DVD_LPCM:
2459         {
2460             MP4_Box_data_sample_soun_t *p_soun = p_sample->data.p_sample_soun;
2461             if( p_soun->i_qt_version == 2 &&
2462                 p_soun->i_qt_description > 20 + 28 )
2463             {
2464                 /* Flags:
2465                  *  0x01: IsFloat
2466                  *  0x02: IsBigEndian
2467                  *  0x04: IsSigned
2468                  */
2469                 static const struct {
2470                     unsigned     i_flags;
2471                     unsigned     i_mask;
2472                     unsigned     i_bits;
2473                     vlc_fourcc_t i_codec;
2474                 } p_formats[] = {
2475                     { 0x01,           0x03, 32, VLC_CODEC_F32L },
2476                     { 0x01,           0x03, 64, VLC_CODEC_F64L },
2477                     { 0x01|0x02,      0x03, 32, VLC_CODEC_F32B },
2478                     { 0x01|0x02,      0x03, 64, VLC_CODEC_F64B },
2479
2480                     { 0x00,           0x05,  8, VLC_CODEC_U8 },
2481                     { 0x00|     0x04, 0x05,  8, VLC_CODEC_S8 },
2482
2483                     { 0x00,           0x07, 16, VLC_CODEC_U16L },
2484                     { 0x00|0x02,      0x07, 16, VLC_CODEC_U16B },
2485                     { 0x00     |0x04, 0x07, 16, VLC_CODEC_S16L },
2486                     { 0x00|0x02|0x04, 0x07, 16, VLC_CODEC_S16B },
2487
2488                     { 0x00,           0x07, 24, VLC_CODEC_U24L },
2489                     { 0x00|0x02,      0x07, 24, VLC_CODEC_U24B },
2490                     { 0x00     |0x04, 0x07, 24, VLC_CODEC_S24L },
2491                     { 0x00|0x02|0x04, 0x07, 24, VLC_CODEC_S24B },
2492
2493                     { 0x00,           0x07, 32, VLC_CODEC_U32L },
2494                     { 0x00|0x02,      0x07, 32, VLC_CODEC_U32B },
2495                     { 0x00     |0x04, 0x07, 32, VLC_CODEC_S32L },
2496                     { 0x00|0x02|0x04, 0x07, 32, VLC_CODEC_S32B },
2497
2498                     {0, 0, 0, 0}
2499                 };
2500                 uint32_t i_bits  = GetDWBE(&p_soun->p_qt_description[20 + 20]);
2501                 uint32_t i_flags = GetDWBE(&p_soun->p_qt_description[20 + 24]);
2502
2503                 for( int i = 0; p_formats[i].i_codec; i++ )
2504                 {
2505                     if( p_formats[i].i_bits == i_bits &&
2506                         (i_flags & p_formats[i].i_mask) == p_formats[i].i_flags )
2507                     {
2508                         p_track->fmt.i_codec = p_formats[i].i_codec;
2509                         p_track->fmt.audio.i_bitspersample = i_bits;
2510                         p_track->fmt.audio.i_blockalign = p_soun->i_channelcount * i_bits / 8;
2511                         p_track->i_sample_size = p_track->fmt.audio.i_blockalign;
2512
2513                         p_soun->i_qt_version = 0;
2514                         break;
2515                     }
2516                 }
2517             }
2518             break;
2519         }
2520         default:
2521             p_track->fmt.i_codec = p_sample->i_type;
2522             break;
2523     }
2524
2525     /* now see if esds is present and if so create a data packet
2526         with decoder_specific_info  */
2527 #define p_decconfig p_esds->data.p_esds->es_descriptor.p_decConfigDescr
2528     if( ( ( p_esds = MP4_BoxGet( p_sample, "esds" ) ) ||
2529           ( p_esds = MP4_BoxGet( p_sample, "wave/esds" ) ) )&&
2530         ( p_esds->data.p_esds )&&
2531         ( p_decconfig ) )
2532     {
2533         /* First update information based on i_objectTypeIndication */
2534         switch( p_decconfig->i_objectTypeIndication )
2535         {
2536             case( 0x20 ): /* MPEG4 VIDEO */
2537                 p_track->fmt.i_codec = VLC_CODEC_MP4V;
2538                 break;
2539             case( 0x21 ): /* H.264 */
2540                 p_track->fmt.i_codec = VLC_CODEC_H264;
2541                 break;
2542             case( 0x40):
2543                 p_track->fmt.i_codec = VLC_CODEC_MP4A;
2544                 if( p_decconfig->i_decoder_specific_info_len >= 2 &&
2545                      p_decconfig->p_decoder_specific_info[0]       == 0xF8 &&
2546                     (p_decconfig->p_decoder_specific_info[1]&0xE0) == 0x80 )
2547                 {
2548                     p_track->fmt.i_codec = VLC_CODEC_ALS;
2549                 }
2550                 break;
2551             case( 0x60):
2552             case( 0x61):
2553             case( 0x62):
2554             case( 0x63):
2555             case( 0x64):
2556             case( 0x65): /* MPEG2 video */
2557                 p_track->fmt.i_codec = VLC_CODEC_MPGV;
2558                 break;
2559             /* Theses are MPEG2-AAC */
2560             case( 0x66): /* main profile */
2561             case( 0x67): /* Low complexity profile */
2562             case( 0x68): /* Scaleable Sampling rate profile */
2563                 p_track->fmt.i_codec = VLC_CODEC_MP4A;
2564                 break;
2565             /* True MPEG 2 audio */
2566             case( 0x69):
2567                 p_track->fmt.i_codec = VLC_CODEC_MPGA;
2568                 break;
2569             case( 0x6a): /* MPEG1 video */
2570                 p_track->fmt.i_codec = VLC_CODEC_MPGV;
2571                 break;
2572             case( 0x6b): /* MPEG1 audio */
2573                 p_track->fmt.i_codec = VLC_CODEC_MPGA;
2574                 break;
2575             case( 0x6c ): /* jpeg */
2576                 p_track->fmt.i_codec = VLC_CODEC_JPEG;
2577                 break;
2578             case( 0x6d ): /* png */
2579                 p_track->fmt.i_codec = VLC_CODEC_PNG;
2580                 break;
2581             case( 0x6e ): /* jpeg2000 */
2582                 p_track->fmt.i_codec = VLC_FOURCC( 'M','J','2','C' );
2583                 break;
2584             case( 0xa3 ): /* vc1 */
2585                 p_track->fmt.i_codec = VLC_CODEC_VC1;
2586                 break;
2587             case( 0xa4 ):
2588                 p_track->fmt.i_codec = VLC_CODEC_DIRAC;
2589                 break;
2590             case( 0xa5 ):
2591                 p_track->fmt.i_codec = VLC_CODEC_A52;
2592                 break;
2593             case( 0xa6 ):
2594                 p_track->fmt.i_codec = VLC_CODEC_EAC3;
2595                 break;
2596             case( 0xa9 ): /* dts */
2597             case( 0xaa ): /* DTS-HD HRA */
2598             case( 0xab ): /* DTS-HD Master Audio */
2599                 p_track->fmt.i_codec = VLC_CODEC_DTS;
2600                 break;
2601             case( 0xDD ):
2602                 p_track->fmt.i_codec = VLC_CODEC_VORBIS;
2603                 break;
2604
2605             /* Private ID */
2606             case( 0xe0 ): /* NeroDigital: dvd subs */
2607                 if( p_track->fmt.i_cat == SPU_ES )
2608                 {
2609                     p_track->fmt.i_codec = VLC_CODEC_SPU;
2610                     if( p_track->i_width > 0 )
2611                         p_track->fmt.subs.spu.i_original_frame_width = p_track->i_width;
2612                     if( p_track->i_height > 0 )
2613                         p_track->fmt.subs.spu.i_original_frame_height = p_track->i_height;
2614                     break;
2615                 }
2616             case( 0xe1 ): /* QCelp for 3gp */
2617                 if( p_track->fmt.i_cat == AUDIO_ES )
2618                 {
2619                     p_track->fmt.i_codec = VLC_CODEC_QCELP;
2620                 }
2621                 break;
2622
2623             /* Fallback */
2624             default:
2625                 /* Unknown entry, but don't touch i_fourcc */
2626                 msg_Warn( p_demux,
2627                           "unknown objectTypeIndication(0x%x) (Track[ID 0x%x])",
2628                           p_decconfig->i_objectTypeIndication,
2629                           p_track->i_track_ID );
2630                 break;
2631         }
2632         p_track->fmt.i_extra = p_decconfig->i_decoder_specific_info_len;
2633         if( p_track->fmt.i_extra > 0 )
2634         {
2635             p_track->fmt.p_extra = malloc( p_track->fmt.i_extra );
2636             memcpy( p_track->fmt.p_extra, p_decconfig->p_decoder_specific_info,
2637                     p_track->fmt.i_extra );
2638         }
2639         if( p_track->fmt.i_codec == VLC_CODEC_SPU &&
2640             p_track->fmt.i_extra >= 16 * 4 )
2641         {
2642             for( int i = 0; i < 16; i++ )
2643             {
2644                 p_track->fmt.subs.spu.palette[1 + i] =
2645                             GetDWBE((char*)p_track->fmt.p_extra + i * 4);
2646             }
2647             p_track->fmt.subs.spu.palette[0] = 0xBeef;
2648         }
2649     }
2650     else
2651     {
2652         switch( p_sample->i_type )
2653         {
2654             /* qt decoder, send the complete chunk */
2655             case VLC_FOURCC ('h', 'd', 'v', '1'): // HDV 720p30
2656             case VLC_FOURCC ('h', 'd', 'v', '2'): // HDV 1080i60
2657             case VLC_FOURCC ('h', 'd', 'v', '3'): // HDV 1080i50
2658             case VLC_FOURCC ('h', 'd', 'v', '5'): // HDV 720p25
2659             case VLC_FOURCC ('m', 'x', '5', 'n'): // MPEG2 IMX NTSC 525/60 50mb/s produced by FCP
2660             case VLC_FOURCC ('m', 'x', '5', 'p'): // MPEG2 IMX PAL 625/60 50mb/s produced by FCP
2661             case VLC_FOURCC ('m', 'x', '4', 'n'): // MPEG2 IMX NTSC 525/60 40mb/s produced by FCP
2662             case VLC_FOURCC ('m', 'x', '4', 'p'): // MPEG2 IMX PAL 625/60 40mb/s produced by FCP
2663             case VLC_FOURCC ('m', 'x', '3', 'n'): // MPEG2 IMX NTSC 525/60 30mb/s produced by FCP
2664             case VLC_FOURCC ('m', 'x', '3', 'p'): // MPEG2 IMX PAL 625/50 30mb/s produced by FCP
2665             case VLC_FOURCC ('x', 'd', 'v', '2'): // XDCAM HD 1080i60
2666             case VLC_FOURCC ('A', 'V', 'm', 'p'): // AVID IMX PAL
2667                 p_track->fmt.i_codec = VLC_CODEC_MPGV;
2668                 break;
2669             /* qt decoder, send the complete chunk */
2670             case VLC_CODEC_SVQ1:
2671             case VLC_CODEC_SVQ3:
2672             case VLC_FOURCC( 'V', 'P', '3', '1' ):
2673             case VLC_FOURCC( '3', 'I', 'V', '1' ):
2674             case VLC_FOURCC( 'Z', 'y', 'G', 'o' ):
2675                 p_track->fmt.i_extra =
2676                     p_sample->data.p_sample_vide->i_qt_image_description;
2677                 if( p_track->fmt.i_extra > 0 )
2678                 {
2679                     p_track->fmt.p_extra = malloc( p_track->fmt.i_extra );
2680                     memcpy( p_track->fmt.p_extra,
2681                             p_sample->data.p_sample_vide->p_qt_image_description,
2682                             p_track->fmt.i_extra);
2683                 }
2684                 break;
2685
2686             case VLC_CODEC_AMR_NB:
2687                 p_track->fmt.audio.i_rate = 8000;
2688                 break;
2689             case VLC_CODEC_AMR_WB:
2690                 p_track->fmt.audio.i_rate = 16000;
2691                 break;
2692             case VLC_FOURCC( 'Q', 'D', 'M', 'C' ):
2693             case VLC_CODEC_QDM2:
2694             case VLC_CODEC_ALAC:
2695                 p_track->fmt.i_extra =
2696                     p_sample->data.p_sample_soun->i_qt_description;
2697                 if( p_track->fmt.i_extra > 0 )
2698                 {
2699                     p_track->fmt.p_extra = malloc( p_track->fmt.i_extra );
2700                     memcpy( p_track->fmt.p_extra,
2701                             p_sample->data.p_sample_soun->p_qt_description,
2702                             p_track->fmt.i_extra);
2703                 }
2704                 if( p_track->fmt.i_extra == 56 && p_sample->i_type == VLC_CODEC_ALAC )
2705                 {
2706                     p_track->fmt.audio.i_channels = *((uint8_t*)p_track->fmt.p_extra + 41);
2707                     p_track->fmt.audio.i_rate = GetDWBE((uint8_t*)p_track->fmt.p_extra + 52);
2708                 }
2709                 break;
2710
2711             case VLC_FOURCC( 'v', 'c', '-', '1' ):
2712             {
2713                 MP4_Box_t *p_dvc1 = MP4_BoxGet( p_sample, "dvc1" );
2714                 if( p_dvc1 )
2715                 {
2716                     p_track->fmt.i_extra = BOXDATA(p_dvc1)->i_vc1;
2717                     if( p_track->fmt.i_extra > 0 )
2718                     {
2719                         p_track->fmt.p_extra = malloc( BOXDATA(p_dvc1)->i_vc1 );
2720                         memcpy( p_track->fmt.p_extra, BOXDATA(p_dvc1)->p_vc1,
2721                                 p_track->fmt.i_extra );
2722                     }
2723                 }
2724                 else
2725                 {
2726                     msg_Err( p_demux, "missing dvc1" );
2727                 }
2728                 break;
2729             }
2730
2731             /* avc1: send avcC (h264 without annexe B, ie without start code)*/
2732             case VLC_FOURCC( 'a', 'v', 'c', '1' ):
2733             {
2734                 MP4_Box_t *p_avcC = MP4_BoxGet( p_sample, "avcC" );
2735
2736                 if( p_avcC )
2737                 {
2738                     p_track->fmt.i_extra = BOXDATA(p_avcC)->i_avcC;
2739                     if( p_track->fmt.i_extra > 0 )
2740                     {
2741                         p_track->fmt.p_extra = malloc( BOXDATA(p_avcC)->i_avcC );
2742                         memcpy( p_track->fmt.p_extra, BOXDATA(p_avcC)->p_avcC,
2743                                 p_track->fmt.i_extra );
2744                     }
2745                 }
2746                 else
2747                 {
2748                     msg_Err( p_demux, "missing avcC" );
2749                 }
2750                 break;
2751             }
2752             case VLC_FOURCC( 'h', 'v', 'c', '1' ):
2753             case VLC_FOURCC( 'h', 'e', 'v', '1' ):
2754             {
2755                 MP4_Box_t *p_hvcC = MP4_BoxGet( p_sample, "hvcC" );
2756
2757                 if( p_hvcC )
2758                 {
2759                     p_track->fmt.i_extra = p_hvcC->data.p_hvcC->i_hvcC;
2760                     if( p_track->fmt.i_extra > 0 )
2761                     {
2762                         p_track->fmt.p_extra = malloc( p_hvcC->data.p_hvcC->i_hvcC );
2763                         memcpy( p_track->fmt.p_extra, p_hvcC->data.p_hvcC->p_hvcC,
2764                                 p_track->fmt.i_extra );
2765                     }
2766                     p_track->fmt.i_codec = VLC_CODEC_HEVC;
2767                 }
2768                 else
2769                 {
2770                     msg_Err( p_demux, "missing hvcC" );
2771                 }
2772                 break;
2773             }
2774
2775
2776             case VLC_CODEC_ADPCM_MS:
2777             case VLC_CODEC_ADPCM_IMA_WAV:
2778             case VLC_CODEC_QCELP:
2779                 p_track->fmt.audio.i_blockalign = p_sample->data.p_sample_soun->i_bytes_per_frame;
2780                 break;
2781
2782             default:
2783                 msg_Dbg( p_demux, "Unrecognized FourCC %4.4s", (char *)&p_sample->i_type );
2784                 break;
2785         }
2786     }
2787
2788 #undef p_decconfig
2789
2790     if( pp_es )
2791         *pp_es = es_out_Add( p_demux->out, &p_track->fmt );
2792
2793     return VLC_SUCCESS;
2794 }
2795
2796 /* given a time it return sample/chunk
2797  * it also update elst field of the track
2798  */
2799 static int TrackTimeToSampleChunk( demux_t *p_demux, mp4_track_t *p_track,
2800                                    int64_t i_start, uint32_t *pi_chunk,
2801                                    uint32_t *pi_sample )
2802 {
2803     demux_sys_t *p_sys = p_demux->p_sys;
2804     MP4_Box_t   *p_box_stss;
2805     uint64_t     i_dts;
2806     unsigned int i_sample;
2807     unsigned int i_chunk;
2808     int          i_index;
2809
2810     /* FIXME see if it's needed to check p_track->i_chunk_count */
2811     if( p_track->i_chunk_count == 0 )
2812         return( VLC_EGENERIC );
2813
2814     /* handle elst (find the correct one) */
2815     MP4_TrackSetELST( p_demux, p_track, i_start );
2816     if( p_track->p_elst && p_track->BOXDATA(p_elst)->i_entry_count > 0 )
2817     {
2818         MP4_Box_data_elst_t *elst = p_track->BOXDATA(p_elst);
2819         int64_t i_mvt= i_start * p_sys->i_timescale / CLOCK_FREQ;
2820
2821         /* now calculate i_start for this elst */
2822         /* offset */
2823         i_start -= p_track->i_elst_time * CLOCK_FREQ / p_sys->i_timescale;
2824         if( i_start < 0 )
2825         {
2826             *pi_chunk = 0;
2827             *pi_sample= 0;
2828
2829             return VLC_SUCCESS;
2830         }
2831         /* to track time scale */
2832         i_start  = i_start * p_track->i_timescale / CLOCK_FREQ;
2833         /* add elst offset */
2834         if( ( elst->i_media_rate_integer[p_track->i_elst] > 0 ||
2835              elst->i_media_rate_fraction[p_track->i_elst] > 0 ) &&
2836             elst->i_media_time[p_track->i_elst] > 0 )
2837         {
2838             i_start += elst->i_media_time[p_track->i_elst];
2839         }
2840
2841         msg_Dbg( p_demux, "elst (%d) gives %"PRId64"ms (movie)-> %"PRId64
2842                  "ms (track)", p_track->i_elst,
2843                  i_mvt * 1000 / p_sys->i_timescale,
2844                  i_start * 1000 / p_track->i_timescale );
2845     }
2846     else
2847     {
2848         /* convert absolute time to in timescale unit */
2849         i_start = i_start * p_track->i_timescale / CLOCK_FREQ;
2850     }
2851
2852     /* we start from sample 0/chunk 0, hope it won't take too much time */
2853     /* *** find good chunk *** */
2854     for( i_chunk = 0; ; i_chunk++ )
2855     {
2856         if( i_chunk + 1 >= p_track->i_chunk_count )
2857         {
2858             /* at the end and can't check if i_start in this chunk,
2859                it will be check while searching i_sample */
2860             i_chunk = p_track->i_chunk_count - 1;
2861             break;
2862         }
2863
2864         if( (uint64_t)i_start >= p_track->chunk[i_chunk].i_first_dts &&
2865             (uint64_t)i_start <  p_track->chunk[i_chunk + 1].i_first_dts )
2866         {
2867             break;
2868         }
2869     }
2870
2871     /* *** find sample in the chunk *** */
2872     i_sample = p_track->chunk[i_chunk].i_sample_first;
2873     i_dts    = p_track->chunk[i_chunk].i_first_dts;
2874     for( i_index = 0; i_sample < p_track->chunk[i_chunk].i_sample_count; )
2875     {
2876         if( i_dts +
2877             p_track->chunk[i_chunk].p_sample_count_dts[i_index] *
2878             p_track->chunk[i_chunk].p_sample_delta_dts[i_index] < (uint64_t)i_start )
2879         {
2880             i_dts    +=
2881                 p_track->chunk[i_chunk].p_sample_count_dts[i_index] *
2882                 p_track->chunk[i_chunk].p_sample_delta_dts[i_index];
2883
2884             i_sample += p_track->chunk[i_chunk].p_sample_count_dts[i_index];
2885             i_index++;
2886         }
2887         else
2888         {
2889             if( p_track->chunk[i_chunk].p_sample_delta_dts[i_index] <= 0 )
2890             {
2891                 break;
2892             }
2893             i_sample += ( i_start - i_dts ) /
2894                 p_track->chunk[i_chunk].p_sample_delta_dts[i_index];
2895             break;
2896         }
2897     }
2898
2899     if( i_sample >= p_track->i_sample_count )
2900     {
2901         msg_Warn( p_demux, "track[Id 0x%x] will be disabled "
2902                   "(seeking too far) chunk=%d sample=%d",
2903                   p_track->i_track_ID, i_chunk, i_sample );
2904         return( VLC_EGENERIC );
2905     }
2906
2907
2908     /* *** Try to find nearest sync points *** */
2909     if( ( p_box_stss = MP4_BoxGet( p_track->p_stbl, "stss" ) ) )
2910     {
2911         MP4_Box_data_stss_t *p_stss = p_box_stss->data.p_stss;
2912         msg_Dbg( p_demux, "track[Id 0x%x] using Sync Sample Box (stss)",
2913                  p_track->i_track_ID );
2914         for( unsigned i_index = 0; i_index < p_stss->i_entry_count; i_index++ )
2915         {
2916             if( i_index >= p_stss->i_entry_count - 1 ||
2917                 i_sample < p_stss->i_sample_number[i_index+1] )
2918             {
2919                 unsigned i_sync_sample = p_stss->i_sample_number[i_index];
2920                 msg_Dbg( p_demux, "stss gives %d --> %d (sample number)",
2921                          i_sample, i_sync_sample );
2922
2923                 if( i_sync_sample <= i_sample )
2924                 {
2925                     while( i_chunk > 0 &&
2926                            i_sync_sample < p_track->chunk[i_chunk].i_sample_first )
2927                         i_chunk--;
2928                 }
2929                 else
2930                 {
2931                     while( i_chunk < p_track->i_chunk_count - 1 &&
2932                            i_sync_sample >= p_track->chunk[i_chunk].i_sample_first +
2933                                             p_track->chunk[i_chunk].i_sample_count )
2934                         i_chunk++;
2935                 }
2936                 i_sample = i_sync_sample;
2937                 break;
2938             }
2939         }
2940     }
2941     else
2942     {
2943         msg_Dbg( p_demux, "track[Id 0x%x] does not provide Sync "
2944                  "Sample Box (stss)", p_track->i_track_ID );
2945     }
2946
2947     *pi_chunk  = i_chunk;
2948     *pi_sample = i_sample;
2949
2950     return VLC_SUCCESS;
2951 }
2952
2953 static int TrackGotoChunkSample( demux_t *p_demux, mp4_track_t *p_track,
2954                                  unsigned int i_chunk, unsigned int i_sample )
2955 {
2956     bool b_reselect = false;
2957
2958     /* now see if actual es is ok */
2959     if( p_track->i_chunk >= p_track->i_chunk_count ||
2960         p_track->chunk[p_track->i_chunk].i_sample_description_index !=
2961             p_track->chunk[i_chunk].i_sample_description_index )
2962     {
2963         msg_Warn( p_demux, "recreate ES for track[Id 0x%x]",
2964                   p_track->i_track_ID );
2965
2966         es_out_Control( p_demux->out, ES_OUT_GET_ES_STATE,
2967                         p_track->p_es, &b_reselect );
2968
2969         es_out_Del( p_demux->out, p_track->p_es );
2970
2971         p_track->p_es = NULL;
2972
2973         if( TrackCreateES( p_demux, p_track, i_chunk, &p_track->p_es ) )
2974         {
2975             msg_Err( p_demux, "cannot create es for track[Id 0x%x]",
2976                      p_track->i_track_ID );
2977
2978             p_track->b_ok       = false;
2979             p_track->b_selected = false;
2980             return VLC_EGENERIC;
2981         }
2982     }
2983
2984     /* select again the new decoder */
2985     if( b_reselect )
2986     {
2987         es_out_Control( p_demux->out, ES_OUT_SET_ES, p_track->p_es );
2988     }
2989
2990     p_track->i_chunk    = i_chunk;
2991     p_track->i_sample   = i_sample;
2992
2993     return p_track->b_selected ? VLC_SUCCESS : VLC_EGENERIC;
2994 }
2995
2996 /****************************************************************************
2997  * MP4_TrackCreate:
2998  ****************************************************************************
2999  * Parse track information and create all needed data to run a track
3000  * If it succeed b_ok is set to 1 else to 0
3001  ****************************************************************************/
3002 static void MP4_TrackCreate( demux_t *p_demux, mp4_track_t *p_track,
3003                              MP4_Box_t *p_box_trak,
3004                              bool b_force_enable )
3005 {
3006     demux_sys_t *p_sys = p_demux->p_sys;
3007
3008     MP4_Box_t *p_tkhd = MP4_BoxGet( p_box_trak, "tkhd" );
3009     MP4_Box_t *p_tref = MP4_BoxGet( p_box_trak, "tref" );
3010     MP4_Box_t *p_elst;
3011
3012     MP4_Box_t *p_mdhd;
3013     MP4_Box_t *p_udta;
3014     MP4_Box_t *p_hdlr;
3015
3016     MP4_Box_t *p_vmhd;
3017     MP4_Box_t *p_smhd;
3018
3019     char language[4] = { '\0' };
3020
3021     /* hint track unsupported */
3022
3023     /* set default value (-> track unusable) */
3024     p_track->b_ok       = false;
3025     p_track->b_enable   = false;
3026     p_track->b_selected = false;
3027     p_track->b_chapter  = false;
3028     p_track->b_mac_encoding = false;
3029
3030     es_format_Init( &p_track->fmt, UNKNOWN_ES, 0 );
3031
3032     if( !p_tkhd )
3033     {
3034         return;
3035     }
3036
3037     /* do we launch this track by default ? */
3038     p_track->b_enable =
3039         ( ( BOXDATA(p_tkhd)->i_flags&MP4_TRACK_ENABLED ) != 0 );
3040     if( !p_track->b_enable )
3041         p_track->fmt.i_priority = ES_PRIORITY_NOT_DEFAULTABLE;
3042
3043     p_track->i_track_ID = BOXDATA(p_tkhd)->i_track_ID;
3044
3045     p_track->i_width = BOXDATA(p_tkhd)->i_width / BLOCK16x16;
3046     p_track->i_height = BOXDATA(p_tkhd)->i_height / BLOCK16x16;
3047     p_track->f_rotation = BOXDATA(p_tkhd)->f_rotation;
3048
3049     if( p_tref )
3050     {
3051 /*        msg_Warn( p_demux, "unhandled box: tref --> FIXME" ); */
3052     }
3053
3054     p_mdhd = MP4_BoxGet( p_box_trak, "mdia/mdhd" );
3055     p_hdlr = MP4_BoxGet( p_box_trak, "mdia/hdlr" );
3056
3057     if( ( !p_mdhd )||( !p_hdlr ) )
3058     {
3059         return;
3060     }
3061
3062     p_track->i_timescale = BOXDATA(p_mdhd)->i_timescale;
3063     if( p_track->i_timescale == 0 )
3064         return;
3065
3066     if( BOXDATA(p_mdhd)->i_language_code < 0x400 )
3067     {
3068         strcpy( language, MP4_ConvertMacCode( BOXDATA(p_mdhd)->i_language_code ) );
3069         p_track->b_mac_encoding = true;
3070     }
3071     else if( BOXDATA(p_mdhd)->i_language_code == 0x7fff )
3072         p_track->b_mac_encoding = true;
3073     else
3074     {
3075         for( unsigned i = 0; i < 3; i++ )
3076             language[i] = BOXDATA(p_mdhd)->i_language[i];
3077         language[3] = '\0';
3078     }
3079
3080     switch( p_hdlr->data.p_hdlr->i_handler_type )
3081     {
3082         case( ATOM_soun ):
3083             if( !( p_smhd = MP4_BoxGet( p_box_trak, "mdia/minf/smhd" ) ) )
3084             {
3085                 return;
3086             }
3087             p_track->fmt.i_cat = AUDIO_ES;
3088             break;
3089
3090         case( ATOM_vide ):
3091             if( !( p_vmhd = MP4_BoxGet( p_box_trak, "mdia/minf/vmhd" ) ) )
3092             {
3093                 return;
3094             }
3095             p_track->fmt.i_cat = VIDEO_ES;
3096             break;
3097
3098         case( ATOM_tx3g ):
3099         case( ATOM_text ):
3100         case( ATOM_subp ):
3101         case( ATOM_sbtl ):
3102             p_track->fmt.i_codec = VLC_CODEC_TX3G;
3103             p_track->fmt.i_cat = SPU_ES;
3104             break;
3105
3106         default:
3107             return;
3108     }
3109
3110     p_track->i_elst = 0;
3111     p_track->i_elst_time = 0;
3112     if( ( p_track->p_elst = p_elst = MP4_BoxGet( p_box_trak, "edts/elst" ) ) )
3113     {
3114         MP4_Box_data_elst_t *elst = BOXDATA(p_elst);
3115         unsigned int i;
3116
3117         msg_Warn( p_demux, "elst box found" );
3118         for( i = 0; i < elst->i_entry_count; i++ )
3119         {
3120             msg_Dbg( p_demux, "   - [%d] duration=%"PRId64"ms media time=%"PRId64
3121                      "ms) rate=%d.%d", i,
3122                      elst->i_segment_duration[i] * 1000 / p_sys->i_timescale,
3123                      elst->i_media_time[i] >= 0 ?
3124                      (int64_t)(elst->i_media_time[i] * 1000 / p_track->i_timescale) :
3125                      INT64_C(-1),
3126                      elst->i_media_rate_integer[i],
3127                      elst->i_media_rate_fraction[i] );
3128         }
3129     }
3130
3131
3132 /*  TODO
3133     add support for:
3134     p_dinf = MP4_BoxGet( p_minf, "dinf" );
3135 */
3136     if( !( p_track->p_stbl = MP4_BoxGet( p_box_trak,"mdia/minf/stbl" ) ) ||
3137         !( p_track->p_stsd = MP4_BoxGet( p_box_trak,"mdia/minf/stbl/stsd") ) )
3138     {
3139         return;
3140     }
3141
3142     /* Set language */
3143     if( *language && strcmp( language, "```" ) && strcmp( language, "und" ) )
3144     {
3145         p_track->fmt.psz_language = strdup( language );
3146     }
3147
3148     p_udta = MP4_BoxGet( p_box_trak, "udta" );
3149     if( p_udta )
3150     {
3151         MP4_Box_t *p_box_iter;
3152         for( p_box_iter = p_udta->p_first; p_box_iter != NULL;
3153                  p_box_iter = p_box_iter->p_next )
3154         {
3155             switch( p_box_iter->i_type )
3156             {
3157                 case ATOM_0xa9nam:
3158                     p_track->fmt.psz_description =
3159                         strdup( p_box_iter->data.p_0xa9xxx->psz_text );
3160                     break;
3161                 case ATOM_name:
3162                     p_track->fmt.psz_description =
3163                         strdup( p_box_iter->data.p_name->psz_text );
3164                     break;
3165             }
3166         }
3167     }
3168
3169     /* Create chunk index table and sample index table */
3170     if( TrackCreateChunksIndex( p_demux,p_track  ) ||
3171         TrackCreateSamplesIndex( p_demux, p_track ) )
3172     {
3173         msg_Err( p_demux, "cannot create chunks index" );
3174         return; /* cannot create chunks index */
3175     }
3176
3177     p_track->i_chunk  = 0;
3178     p_track->i_sample = 0;
3179
3180     /* Mark chapter only track */
3181     if( p_sys->p_tref_chap )
3182     {
3183         MP4_Box_data_tref_generic_t *p_chap = p_sys->p_tref_chap->data.p_tref_generic;
3184         unsigned int i;
3185
3186         for( i = 0; i < p_chap->i_entry_count; i++ )
3187         {
3188             if( p_track->i_track_ID == p_chap->i_track_ID[i] &&
3189                 p_track->fmt.i_cat == UNKNOWN_ES )
3190             {
3191                 p_track->b_chapter = true;
3192                 p_track->b_enable = false;
3193                 break;
3194             }
3195         }
3196     }
3197
3198     /* now create es */
3199     if( b_force_enable &&
3200         ( p_track->fmt.i_cat == VIDEO_ES || p_track->fmt.i_cat == AUDIO_ES ) )
3201     {
3202         msg_Warn( p_demux, "Enabling track[Id 0x%x] (buggy file without enabled track)",
3203                   p_track->i_track_ID );
3204         p_track->b_enable = true;
3205         p_track->fmt.i_priority = ES_PRIORITY_SELECTABLE_MIN;
3206     }
3207
3208     p_track->p_es = NULL;
3209     if( TrackCreateES( p_demux,
3210                        p_track, p_track->i_chunk,
3211                        p_track->b_chapter ? NULL : &p_track->p_es ) )
3212     {
3213         msg_Err( p_demux, "cannot create es for track[Id 0x%x]",
3214                  p_track->i_track_ID );
3215         return;
3216     }
3217     p_track->b_ok = true;
3218 #if 0
3219     {
3220         int i;
3221         for( i = 0; i < p_track->i_chunk_count; i++ )
3222         {
3223             fprintf( stderr, "%-5d sample_count=%d pts=%lld\n",
3224                      i, p_track->chunk[i].i_sample_count,
3225                      p_track->chunk[i].i_first_dts );
3226
3227         }
3228     }
3229 #endif
3230 }
3231
3232 static void FreeAndResetChunk( mp4_chunk_t *ck )
3233 {
3234     free( ck->p_sample_count_dts );
3235     free( ck->p_sample_delta_dts );
3236     free( ck->p_sample_count_pts );
3237     free( ck->p_sample_offset_pts );
3238     free( ck->p_sample_size );
3239     for( uint32_t i = 0; i < ck->i_sample_count; i++ )
3240         free( ck->p_sample_data[i] );
3241     free( ck->p_sample_data );
3242     memset( ck, 0, sizeof( mp4_chunk_t ) );
3243 }
3244
3245 /****************************************************************************
3246  * MP4_TrackDestroy:
3247  ****************************************************************************
3248  * Destroy a track created by MP4_TrackCreate.
3249  ****************************************************************************/
3250 static void MP4_TrackDestroy( mp4_track_t *p_track )
3251 {
3252     unsigned int i_chunk;
3253
3254     p_track->b_ok = false;
3255     p_track->b_enable   = false;
3256     p_track->b_selected = false;
3257
3258     es_format_Clean( &p_track->fmt );
3259
3260     for( i_chunk = 0; i_chunk < p_track->i_chunk_count; i_chunk++ )
3261     {
3262         if( p_track->chunk )
3263         {
3264            FREENULL(p_track->chunk[i_chunk].p_sample_count_dts);
3265            FREENULL(p_track->chunk[i_chunk].p_sample_delta_dts );
3266
3267            FREENULL(p_track->chunk[i_chunk].p_sample_count_pts);
3268            FREENULL(p_track->chunk[i_chunk].p_sample_offset_pts );
3269         }
3270     }
3271     FREENULL( p_track->chunk );
3272     if( p_track->cchunk ) {
3273         FreeAndResetChunk( p_track->cchunk );
3274         FREENULL( p_track->cchunk );
3275     }
3276
3277     if( !p_track->i_sample_size )
3278     {
3279         FREENULL( p_track->p_sample_size );
3280     }
3281 }
3282
3283 static int MP4_TrackSelect( demux_t *p_demux, mp4_track_t *p_track,
3284                             mtime_t i_start )
3285 {
3286     if( !p_track->b_ok || p_track->b_chapter )
3287     {
3288         return VLC_EGENERIC;
3289     }
3290
3291     if( p_track->b_selected )
3292     {
3293         msg_Warn( p_demux, "track[Id 0x%x] already selected",
3294                   p_track->i_track_ID );
3295         return VLC_SUCCESS;
3296     }
3297
3298     return MP4_TrackSeek( p_demux, p_track, i_start );
3299 }
3300
3301 static void MP4_TrackUnselect( demux_t *p_demux, mp4_track_t *p_track )
3302 {
3303     if( !p_track->b_ok || p_track->b_chapter )
3304     {
3305         return;
3306     }
3307
3308     if( !p_track->b_selected )
3309     {
3310         msg_Warn( p_demux, "track[Id 0x%x] already unselected",
3311                   p_track->i_track_ID );
3312         return;
3313     }
3314     if( p_track->p_es )
3315     {
3316         es_out_Control( p_demux->out, ES_OUT_SET_ES_STATE,
3317                         p_track->p_es, false );
3318     }
3319
3320     p_track->b_selected = false;
3321 }
3322
3323 static int MP4_TrackSeek( demux_t *p_demux, mp4_track_t *p_track,
3324                           mtime_t i_start )
3325 {
3326     uint32_t i_chunk;
3327     uint32_t i_sample;
3328
3329     if( !p_track->b_ok || p_track->b_chapter )
3330         return VLC_EGENERIC;
3331
3332     p_track->b_selected = false;
3333
3334     if( TrackTimeToSampleChunk( p_demux, p_track, i_start,
3335                                 &i_chunk, &i_sample ) )
3336     {
3337         msg_Warn( p_demux, "cannot select track[Id 0x%x]",
3338                   p_track->i_track_ID );
3339         return VLC_EGENERIC;
3340     }
3341
3342     p_track->b_selected = true;
3343     msg_Err( p_demux, "select track[Id 0x%x] %d %d %ld",
3344               p_track->i_track_ID, i_chunk, i_sample, i_start );
3345     if( !TrackGotoChunkSample( p_demux, p_track, i_chunk, i_sample ) )
3346         p_track->b_selected = true;
3347
3348     return p_track->b_selected ? VLC_SUCCESS : VLC_EGENERIC;
3349 }
3350
3351
3352 /*
3353  * 3 types: for audio
3354  *
3355  */
3356 #define QT_V0_MAX_SAMPLES 1024
3357 static uint32_t MP4_TrackSampleSize( mp4_track_t *p_track, uint32_t *pi_nb_samples )
3358 {
3359     uint32_t i_size;
3360     MP4_Box_data_sample_soun_t *p_soun;
3361
3362     if( p_track->i_sample_size == 0 )
3363     {
3364         /* most simple case */
3365         *pi_nb_samples = 1;
3366         return p_track->p_sample_size[p_track->i_sample];
3367     }
3368
3369     if( p_track->fmt.i_cat != AUDIO_ES )
3370     {
3371         *pi_nb_samples = 1;
3372         return p_track->i_sample_size;
3373     }
3374
3375     p_soun = p_track->p_sample->data.p_sample_soun;
3376
3377     if( p_soun->i_qt_version == 1 )
3378     {
3379         uint32_t i_samples = p_track->chunk[p_track->i_chunk].i_sample_count;
3380         if( p_track->fmt.audio.i_blockalign > 1 )
3381             i_samples = p_soun->i_sample_per_packet;
3382         i_size = i_samples / p_soun->i_sample_per_packet;
3383         if ( UINT32_MAX / i_size >= p_soun->i_bytes_per_frame )
3384             i_size *= p_soun->i_bytes_per_frame;
3385         else
3386             i_size = UINT32_MAX;
3387         *pi_nb_samples = i_samples;
3388     }
3389     else if( p_track->i_sample_size > 256 )
3390     {
3391         /* We do that so we don't read too much data
3392          * (in this case we are likely dealing with compressed data) */
3393         i_size = p_track->i_sample_size;
3394         *pi_nb_samples = 1;
3395     }
3396     else
3397     {
3398         mp4_chunk_t *p_chunk = &p_track->chunk[p_track->i_chunk];
3399         int64_t i_length = CLOCK_FREQ / 10;
3400         uint32_t i_samples = 0;
3401         uint32_t i_maxsamples = 0;
3402         for( uint32_t i=p_track->i_sample; i<p_chunk->i_sample_count; i++ )
3403         {
3404             i_length -= CLOCK_FREQ * p_chunk->p_sample_delta_dts[i] / p_track->i_timescale;
3405             if ( i_length < 0 ) break;
3406             i_maxsamples++;
3407         }
3408
3409         i_samples = __MIN( QT_V0_MAX_SAMPLES, i_samples );
3410         i_samples = __MIN( i_maxsamples, i_samples );
3411         if ( i_samples == 0 ) i_samples = 1;
3412         i_size = i_samples * p_track->i_sample_size;
3413         *pi_nb_samples = i_samples;
3414     }
3415
3416     //fprintf( stderr, "size=%d\n", i_size );
3417     return i_size;
3418 }
3419
3420 static uint64_t MP4_TrackGetPos( mp4_track_t *p_track )
3421 {
3422     unsigned int i_sample;
3423     uint64_t i_pos;
3424
3425     i_pos = p_track->chunk[p_track->i_chunk].i_offset;
3426
3427     if( p_track->i_sample_size )
3428     {
3429         MP4_Box_data_sample_soun_t *p_soun =
3430             p_track->p_sample->data.p_sample_soun;
3431
3432         if( p_track->fmt.i_cat != AUDIO_ES || p_soun->i_qt_version == 0 )
3433         {
3434             i_pos += ( p_track->i_sample -
3435                        p_track->chunk[p_track->i_chunk].i_sample_first ) *
3436                      p_track->i_sample_size;
3437         }
3438         else
3439         {
3440             /* we read chunk by chunk unless a blockalign is requested */
3441             if( p_track->fmt.audio.i_blockalign > 1 )
3442                 i_pos += ( p_track->i_sample - p_track->chunk[p_track->i_chunk].i_sample_first ) /
3443                                 p_soun->i_sample_per_packet * p_soun->i_bytes_per_frame;
3444         }
3445     }
3446     else
3447     {
3448         for( i_sample = p_track->chunk[p_track->i_chunk].i_sample_first;
3449              i_sample < p_track->i_sample; i_sample++ )
3450         {
3451             i_pos += p_track->p_sample_size[i_sample];
3452         }
3453     }
3454
3455     return i_pos;
3456 }
3457
3458 static int MP4_TrackNextSample( demux_t *p_demux, mp4_track_t *p_track, uint32_t i_samples )
3459 {
3460     if( p_track->fmt.i_cat == AUDIO_ES && p_track->i_sample_size != 0 )
3461     {
3462         MP4_Box_data_sample_soun_t *p_soun;
3463
3464         p_soun = p_track->p_sample->data.p_sample_soun;
3465
3466         if( p_soun->i_qt_version == 1 )
3467         {
3468             /* we read chunk by chunk unless a blockalign is requested */
3469             if( p_track->fmt.audio.i_blockalign > 1 )
3470                 p_track->i_sample += p_soun->i_sample_per_packet;
3471             else
3472                 p_track->i_sample += p_track->chunk[p_track->i_chunk].i_sample_count;
3473         }
3474         else if( p_track->i_sample_size > 256 )
3475         {
3476             /* We do that so we don't read too much data
3477              * (in this case we are likely dealing with compressed data) */
3478             p_track->i_sample += 1;
3479         }
3480         else
3481         {
3482             /* FIXME */
3483             p_track->i_sample += i_samples;
3484             if( p_track->i_sample >
3485                 p_track->chunk[p_track->i_chunk].i_sample_first +
3486                 p_track->chunk[p_track->i_chunk].i_sample_count )
3487             {
3488                 p_track->i_sample =
3489                     p_track->chunk[p_track->i_chunk].i_sample_first +
3490                     p_track->chunk[p_track->i_chunk].i_sample_count;
3491             }
3492         }
3493     }
3494     else
3495     {
3496         p_track->i_sample++;
3497     }
3498
3499     if( p_track->i_sample >= p_track->i_sample_count )
3500         return VLC_EGENERIC;
3501
3502     /* Have we changed chunk ? */
3503     if( p_track->i_sample >=
3504             p_track->chunk[p_track->i_chunk].i_sample_first +
3505             p_track->chunk[p_track->i_chunk].i_sample_count )
3506     {
3507         if( TrackGotoChunkSample( p_demux, p_track, p_track->i_chunk + 1,
3508                                   p_track->i_sample ) )
3509         {
3510             msg_Warn( p_demux, "track[0x%x] will be disabled "
3511                       "(cannot restart decoder)", p_track->i_track_ID );
3512             MP4_TrackUnselect( p_demux, p_track );
3513             return VLC_EGENERIC;
3514         }
3515     }
3516
3517     /* Have we changed elst */
3518     if( p_track->p_elst && p_track->BOXDATA(p_elst)->i_entry_count > 0 )
3519     {
3520         demux_sys_t *p_sys = p_demux->p_sys;
3521         MP4_Box_data_elst_t *elst = p_track->BOXDATA(p_elst);
3522         uint64_t i_mvt = MP4_TrackGetDTS( p_demux, p_track ) *
3523                         p_sys->i_timescale / CLOCK_FREQ;
3524
3525         if( (unsigned int)p_track->i_elst < elst->i_entry_count &&
3526             i_mvt >= p_track->i_elst_time +
3527                      elst->i_segment_duration[p_track->i_elst] )
3528         {
3529             MP4_TrackSetELST( p_demux, p_track,
3530                               MP4_TrackGetDTS( p_demux, p_track ) );
3531         }
3532     }
3533
3534     return VLC_SUCCESS;
3535 }
3536
3537 static void MP4_TrackSetELST( demux_t *p_demux, mp4_track_t *tk,
3538                               int64_t i_time )
3539 {
3540     demux_sys_t *p_sys = p_demux->p_sys;
3541     int         i_elst_last = tk->i_elst;
3542
3543     /* handle elst (find the correct one) */
3544     tk->i_elst      = 0;
3545     tk->i_elst_time = 0;
3546     if( tk->p_elst && tk->BOXDATA(p_elst)->i_entry_count > 0 )
3547     {
3548         MP4_Box_data_elst_t *elst = tk->BOXDATA(p_elst);
3549         int64_t i_mvt= i_time * p_sys->i_timescale / CLOCK_FREQ;
3550
3551         for( tk->i_elst = 0; (unsigned int)tk->i_elst < elst->i_entry_count; tk->i_elst++ )
3552         {
3553             mtime_t i_dur = elst->i_segment_duration[tk->i_elst];
3554
3555             if( tk->i_elst_time <= i_mvt && i_mvt < tk->i_elst_time + i_dur )
3556             {
3557                 break;
3558             }
3559             tk->i_elst_time += i_dur;
3560         }
3561
3562         if( (unsigned int)tk->i_elst >= elst->i_entry_count )
3563         {
3564             /* msg_Dbg( p_demux, "invalid number of entry in elst" ); */
3565             tk->i_elst = elst->i_entry_count - 1;
3566             tk->i_elst_time -= elst->i_segment_duration[tk->i_elst];
3567         }
3568
3569         if( elst->i_media_time[tk->i_elst] < 0 )
3570         {
3571             /* track offset */
3572             tk->i_elst_time += elst->i_segment_duration[tk->i_elst];
3573         }
3574     }
3575     if( i_elst_last != tk->i_elst )
3576     {
3577         msg_Warn( p_demux, "elst old=%d new=%d", i_elst_last, tk->i_elst );
3578     }
3579 }
3580
3581 /* */
3582 static const char *MP4_ConvertMacCode( uint16_t i_code )
3583 {
3584     static const struct { const char psz_iso639_1[3]; uint16_t i_code; } p_cvt[] = {
3585         { "en",   0 }, { "fr",   1 }, { "de",   2 }, { "it",   3 }, { "nl",   4 },
3586         { "sv",   5 }, { "es",   6 }, { "da",   7 }, { "pt",   8 }, { "no",   9 },
3587         { "he",  10 }, { "ja",  11 }, { "ar",  12 }, { "fi",  13 }, { "el",  14 },
3588         { "is",  15 }, { "mt",  16 }, { "tr",  17 }, { "hr",  18 }, { "zh",  19 },
3589         { "ur",  20 }, { "hi",  21 }, { "th",  22 }, { "ko",  23 }, { "lt",  24 },
3590         { "pl",  25 }, { "hu",  26 }, { "et",  27 }, { "lv",  28 }, //{ "??",  29 },
3591         { "fo",  30 }, { "fa",  31 }, { "ru",  32 }, { "zh",  33 }, { "nl",  34 },
3592         { "ga",  35 }, { "sq",  36 }, { "ro",  37 }, { "cs",  38 }, { "sk",  39 },
3593         { "sl",  40 }, { "yi",  41 }, { "sr",  42 }, { "mk",  43 }, { "bg",  44 },
3594         { "uk",  45 }, { "be",  46 }, { "uz",  47 }, { "az",  48 }, { "kk",  48 },
3595         { "az",  50 }, { "hy",  51 }, { "ka",  52 }, { "mo",  53 }, { "ky",  54 },
3596         { "tg",  55 }, { "tk",  56 }, { "mn",  57 }, { "mn",  58 }, { "ps",  59 },
3597         { "ku",  60 }, { "ks",  61 }, { "sd",  62 }, { "bo",  63 }, { "ne",  64 },
3598         { "sa",  65 }, { "mr",  66 }, { "bn",  67 }, { "as",  68 }, { "gu",  69 },
3599         { "pa",  70 }, { "or",  71 }, { "ml",  72 }, { "kn",  73 }, { "ta",  74 },
3600         { "te",  75 }, { "si",  76 }, { "my",  77 }, { "km",  78 }, { "lo",  79 },
3601         { "vi",  80 }, { "id",  81 }, { "tl",  82 }, { "ms",  83 }, { "ms",  84 },
3602         { "am",  85 }, { "ti",  86 }, { "om",  87 }, { "so",  88 }, { "sw",  89 },
3603         { "rw",  90 }, { "rn",  91 }, { "ny",  92 }, { "mg",  93 }, { "eo",  94 },
3604
3605                                                      { "cy", 128 }, { "eu", 129 },
3606         { "ca", 130 }, { "la", 131 }, { "qu", 132 }, { "gn", 133 }, { "ay", 134 },
3607         { "tt", 135 }, { "ug", 136 }, { "dz", 137 }, { "jv", 138 }, { "su", 139 },
3608         { "gl", 140 }, { "af", 141 }, { "br", 142 }, { "iu", 143 }, { "gd", 144 },
3609         { "gv", 145 }, { "ga", 146 }, { "to", 147 }, { "el", 148 },
3610         /* */
3611         { "", 0 }
3612     };
3613     int i;
3614     for( i = 0; *p_cvt[i].psz_iso639_1; i++ )
3615     {
3616         if( p_cvt[i].i_code == i_code )
3617             return p_cvt[i].psz_iso639_1;
3618     }
3619     return "";
3620 }
3621
3622 /******************************************************************************
3623  *     Here are the functions used for fragmented MP4
3624  *****************************************************************************/
3625
3626 /**
3627  * It computes the sample rate for a video track using current video chunk
3628  */
3629 static void ChunkGetESSampleRate( unsigned *pi_num, unsigned *pi_den,
3630                                   const mp4_track_t *p_track )
3631 {
3632     if( p_track->cchunk->i_last_dts == 0 )
3633         return;
3634
3635     *pi_num = 0;
3636     *pi_den = 0;
3637
3638     /* */
3639     const mp4_chunk_t *p_chunk = p_track->cchunk;
3640
3641     uint32_t i_sample = p_chunk->i_sample_count;
3642     uint64_t i_first_dts = p_chunk->i_first_dts;
3643     uint64_t i_last_dts =  p_chunk->i_last_dts;
3644
3645     if( i_sample > 1 && i_first_dts < i_last_dts )
3646         vlc_ureduce( pi_num, pi_den,
3647                      ( i_sample - 1) *  p_track->i_timescale,
3648                      i_last_dts - i_first_dts,
3649                      UINT16_MAX);
3650 }
3651
3652 /**
3653  * Build raw avcC box (without the 8 bytes header)
3654  * \return The size of the box.
3655  */
3656 static int build_raw_avcC( uint8_t **p_extra, const uint8_t *CodecPrivateData,
3657                                                        const unsigned cpd_len )
3658 {
3659     uint8_t *avcC;
3660     unsigned sps_len = 0, pps_len = 0;
3661     const uint32_t mark = 0x00000001;
3662
3663     assert( CodecPrivateData[0] == 0 );
3664     assert( CodecPrivateData[1] == 0 );
3665     assert( CodecPrivateData[2] == 0 );
3666     assert( CodecPrivateData[3] == 1 );
3667
3668     uint32_t length = cpd_len + 3;
3669     avcC = calloc( length, 1 );
3670     if( unlikely( avcC == NULL ) )
3671         return 0;
3672
3673     uint8_t *sps = avcC + 8;
3674
3675     uint32_t candidate = ~mark;
3676     CodecPrivateData += 4;
3677     for( unsigned i = 0; i < cpd_len - 4; i++ )
3678     {
3679         sps[i] = CodecPrivateData[i];
3680         candidate = (candidate << 8) | CodecPrivateData[i];
3681         if( candidate == mark )
3682         {
3683             sps_len = i - 3;
3684             break;
3685         }
3686     }
3687     if( sps_len == 0 )
3688     {
3689         free( avcC );
3690         return 0;
3691     }
3692     uint8_t *pps = sps + sps_len + 3;
3693     pps_len = cpd_len - sps_len - 4 * 2;
3694     memcpy( pps, CodecPrivateData + sps_len + 4, pps_len );
3695
3696     /* XXX */
3697     uint8_t AVCProfileIndication = 0x64;
3698     uint8_t profile_compatibility = 0x40;
3699     uint8_t AVCLevelIndication = 0x1f;
3700     uint8_t lengthSizeMinusOne = 0x03;
3701
3702     avcC[0] = 1;
3703     avcC[1] = AVCProfileIndication;
3704     avcC[2] = profile_compatibility;
3705     avcC[3] = AVCLevelIndication;
3706     avcC[4] = 0xfc + lengthSizeMinusOne;
3707     avcC[5] = 0xe0 + 1;
3708     avcC[6] = (sps_len & 0xff00)>>8;
3709     avcC[7] = sps_len & 0xff;
3710
3711     avcC[8+sps_len] = 1;
3712     avcC[9+sps_len] = (pps_len & 0xff00) >> 8;
3713     avcC[10+sps_len] = pps_len & 0xff;
3714
3715     *p_extra = avcC;
3716     return length;
3717 }
3718
3719 /**
3720  * Build a mp4_track_t from a StraBox
3721  */
3722
3723 static inline int MP4_SetCodecExtraData( es_format_t *fmt, MP4_Box_data_stra_t *p_data )
3724 {
3725     fmt->i_extra = p_data->cpd_len;
3726     fmt->p_extra = malloc( p_data->cpd_len );
3727     if( unlikely( !fmt->p_extra ) )
3728         return VLC_ENOMEM;
3729     memcpy( fmt->p_extra, p_data->CodecPrivateData, p_data->cpd_len );
3730     return VLC_SUCCESS;
3731   }
3732
3733 static int MP4_frg_TrackCreate( demux_t *p_demux, mp4_track_t *p_track, MP4_Box_t *p_stra )
3734 {
3735     demux_sys_t *p_sys = p_demux->p_sys;
3736     int ret;
3737     MP4_Box_data_stra_t *p_data = BOXDATA(p_stra);
3738     if( !p_data )
3739         return VLC_EGENERIC;
3740
3741     p_track->b_ok       = true;
3742     p_track->b_selected = false;
3743     p_track->i_sample_count = UINT32_MAX;
3744
3745     p_track->i_timescale = p_sys->i_timescale;
3746     p_track->i_width = p_data->MaxWidth;
3747     p_track->i_height = p_data->MaxHeight;
3748     p_track->i_track_ID = p_data->i_track_ID;
3749
3750     es_format_t *fmt = &p_track->fmt;
3751     if( fmt == NULL )
3752         return VLC_EGENERIC;
3753
3754     es_format_Init( fmt, p_data->i_es_cat, 0 );
3755
3756     /* Set language FIXME */
3757     fmt->psz_language = strdup( "en" );
3758
3759     fmt->i_original_fourcc = p_data->FourCC;
3760     fmt->i_codec = vlc_fourcc_GetCodec( fmt->i_cat, p_data->FourCC );
3761
3762     uint8_t **p_extra = (uint8_t **)&fmt->p_extra;
3763     /* See http://msdn.microsoft.com/en-us/library/ff728116%28v=vs.90%29.aspx
3764      * for MS weird use of FourCC*/
3765     switch( fmt->i_cat )
3766     {
3767         case VIDEO_ES:
3768             if( p_data->FourCC == VLC_FOURCC( 'A', 'V', 'C', '1' ) ||
3769                 p_data->FourCC == VLC_FOURCC( 'A', 'V', 'C', 'B' ) ||
3770                 p_data->FourCC == VLC_FOURCC( 'H', '2', '6', '4' ) )
3771             {
3772                 fmt->i_extra = build_raw_avcC( p_extra,
3773                         p_data->CodecPrivateData, p_data->cpd_len );
3774             }
3775             else
3776             {
3777                 ret = MP4_SetCodecExtraData( fmt, p_data );
3778                 if( ret != VLC_SUCCESS )
3779                     return ret;
3780             }
3781
3782             fmt->video.i_width = p_data->MaxWidth;
3783             fmt->video.i_height = p_data->MaxHeight;
3784             fmt->video.i_bits_per_pixel = 0x18;
3785             fmt->video.i_visible_width = p_data->MaxWidth;
3786             fmt->video.i_visible_height = p_data->MaxHeight;
3787
3788             /* Frame rate */
3789             ChunkGetESSampleRate( &fmt->video.i_frame_rate,
3790                                   &fmt->video.i_frame_rate_base, p_track );
3791
3792             if( fmt->video.i_frame_rate_base != 0 )
3793             {
3794                 p_demux->p_sys->f_fps = (float)fmt->video.i_frame_rate /
3795                                         (float)fmt->video.i_frame_rate_base;
3796             }
3797             else
3798                 p_demux->p_sys->f_fps = 24;
3799
3800             break;
3801
3802         case AUDIO_ES:
3803             fmt->audio.i_channels = p_data->Channels;
3804             fmt->audio.i_rate = p_data->SamplingRate;
3805             fmt->audio.i_bitspersample = p_data->BitsPerSample;
3806             fmt->audio.i_blockalign = p_data->nBlockAlign;
3807
3808             fmt->i_bitrate = p_data->Bitrate;
3809
3810             ret = MP4_SetCodecExtraData( fmt, p_data );
3811             if( ret != VLC_SUCCESS )
3812                 return ret;
3813
3814             break;
3815
3816         default:
3817             break;
3818     }
3819
3820     return VLC_SUCCESS;
3821 }
3822
3823 /**
3824  * Return the track identified by tid
3825  */
3826 static mp4_track_t *MP4_frg_GetTrackByID( demux_t *p_demux, const uint32_t tid )
3827 {
3828     demux_sys_t *p_sys = p_demux->p_sys;
3829
3830     mp4_track_t *ret = NULL;
3831     for( unsigned i = 0; i < p_sys->i_tracks; i++ )
3832     {
3833         ret = &p_sys->track[i];
3834         if( ret->i_track_ID == tid )
3835             return ret;
3836     }
3837     msg_Err( p_demux, "MP4_frg_GetTrack: track %"PRIu32" not found!", tid );
3838     return NULL;
3839 }
3840
3841 static void FlushChunk( demux_t *p_demux, mp4_track_t *tk )
3842 {
3843     msg_Dbg( p_demux, "Flushing chunk for track id %u", tk->i_track_ID );
3844     mp4_chunk_t *ck = tk->cchunk;
3845     while( ck->i_sample < ck->i_sample_count )
3846     {
3847         block_t *p_block;
3848         int64_t i_delta;
3849
3850         if( ck->p_sample_size == NULL || ck->p_sample_data == NULL )
3851             return;
3852
3853         uint32_t sample_size = ck->p_sample_size[ck->i_sample];
3854         assert( sample_size > 0 );
3855         p_block = block_Alloc( sample_size );
3856         if( unlikely( !p_block ) )
3857             return;
3858
3859         uint8_t *src = ck->p_sample_data[ck->i_sample];
3860         memcpy( p_block->p_buffer, src, sample_size );
3861         ck->i_sample++;
3862
3863         /* dts */
3864         p_block->i_dts = VLC_TS_0 + MP4_TrackGetDTS( p_demux, tk );
3865         /* pts */
3866         i_delta = MP4_TrackGetPTSDelta( p_demux, tk );
3867         if( i_delta != -1 )
3868             p_block->i_pts = p_block->i_dts + i_delta;
3869         else if( tk->fmt.i_cat != VIDEO_ES )
3870             p_block->i_pts = p_block->i_dts;
3871         else
3872             p_block->i_pts = VLC_TS_INVALID;
3873
3874         es_out_Send( p_demux->out, tk->p_es, p_block );
3875
3876         tk->i_sample++;
3877     }
3878 }
3879
3880 /**
3881  * Re-init decoder.
3882  * \Note If we call that function too soon,
3883  * before the track has been selected by MP4_TrackSelect
3884  * (during the first execution of Demux), then the track gets disabled
3885  */
3886 static int ReInitDecoder( demux_t *p_demux, mp4_track_t *p_track )
3887 {
3888     demux_sys_t *p_sys = p_demux->p_sys;
3889
3890     uint32_t i_sample = 0;
3891     bool b_smooth = false;
3892     MP4_Box_t *p_stra = NULL, *p_trak = NULL;
3893
3894     if( !CmpUUID( &p_sys->p_root->p_first->i_uuid, &SmooBoxUUID ) )
3895         b_smooth = true;
3896
3897     if( b_smooth )
3898     {
3899         p_stra = MP4_BoxGet( p_sys->p_root, "uuid/uuid[0]" );
3900         if( !p_stra || CmpUUID( &p_stra->i_uuid, &StraBoxUUID ) )
3901             return VLC_EGENERIC;
3902     }
3903     else /* DASH */
3904     {
3905         p_trak = MP4_BoxGet( p_sys->p_root, "/moov/trak[0]" );
3906         if( !p_trak )
3907             return VLC_EGENERIC;
3908     }
3909
3910     i_sample = p_track->i_sample;
3911     es_out_Del( p_demux->out, p_track->p_es );
3912     es_format_Clean( &p_track->fmt );
3913
3914     if( b_smooth )
3915         MP4_frg_TrackCreate( p_demux, p_track, p_stra );
3916     else /* DASH */
3917         MP4_TrackCreate( p_demux, p_track, p_trak, true );
3918
3919     p_track->i_sample = i_sample;
3920
3921     /* Temporary hack until we support track selection */
3922     p_track->b_selected = true;
3923     p_track->b_ok = true;
3924     p_track->b_enable = true;
3925
3926     p_track->p_es = es_out_Add( p_demux->out, &p_track->fmt );
3927     p_track->b_codec_need_restart = false;
3928
3929     return VLC_SUCCESS;
3930 }
3931
3932 /**
3933  * This function fills a mp4_chunk_t structure from a MP4_Box_t (p_chunk).
3934  * The 'i_tk_id' argument returns the ID of the track the chunk belongs to.
3935  * \note p_chunk usually contains a 'moof' and a 'mdat', and might contain a 'sidx'.
3936  * \return VLC_SUCCESS, VLC_EGENERIC or VLC_ENOMEM.
3937  */
3938 static int MP4_frg_GetChunk( demux_t *p_demux, MP4_Box_t *p_chunk, unsigned *i_tk_id )
3939 {
3940     MP4_Box_t *p_sidx = MP4_BoxGet( p_chunk, "sidx" );
3941     MP4_Box_t *p_moof = MP4_BoxGet( p_chunk, "moof" );
3942     if( p_moof == NULL)
3943     {
3944         msg_Warn( p_demux, "no moof box found!" );
3945         return VLC_EGENERIC;
3946     }
3947
3948     MP4_Box_t *p_traf = MP4_BoxGet( p_moof, "traf" );
3949     if( p_traf == NULL)
3950     {
3951         msg_Warn( p_demux, "no traf box found!" );
3952         return VLC_EGENERIC;
3953     }
3954
3955     MP4_Box_t *p_tfhd = MP4_BoxGet( p_traf, "tfhd" );
3956     if( p_tfhd == NULL)
3957     {
3958         msg_Warn( p_demux, "no tfhd box found!" );
3959         return VLC_EGENERIC;
3960     }
3961
3962     uint32_t i_track_ID = BOXDATA(p_tfhd)->i_track_ID;
3963     *i_tk_id = i_track_ID;
3964     assert( i_track_ID > 0 );
3965     msg_Dbg( p_demux, "GetChunk: track ID is %"PRIu32"", i_track_ID );
3966
3967     mp4_track_t *p_track = MP4_frg_GetTrackByID( p_demux, i_track_ID );
3968     if( !p_track )
3969         return VLC_EGENERIC;
3970
3971     mp4_chunk_t *ret = p_track->cchunk;
3972
3973     if( BOXDATA(p_tfhd)->b_empty )
3974         msg_Warn( p_demux, "No samples in this chunk!" );
3975
3976     /* Usually we read 100 ms of each track. However, suppose we have two tracks,
3977      * Ta and Tv (audio and video). Suppose also that Ta is the first track to be
3978      * read, i.e. we read 100 ms of Ta, then 100 ms of Tv, then 100 ms of Ta,
3979      * and so on. Finally, suppose that we get the chunks the other way around,
3980      * i.e. first a chunk of Tv, then a chunk of Ta, then a chunk of Tv, and so on.
3981      * In that case, it is very likely that at some point, Ta->cchunk or Tv->cchunk
3982      * is not emptied when MP4_frg_GetChunks is called. It is therefore necessary to
3983      * flush it, i.e. send to the decoder the samples not yet sent.
3984      * Note that all the samples to be flushed should worth less than 100 ms,
3985      * (though I did not do the formal proof) and thus this flushing mechanism
3986      * should not cause A/V sync issues, or delays or whatever.
3987      */
3988     if( ret->i_sample < ret->i_sample_count )
3989         FlushChunk( p_demux, p_track );
3990
3991     if( ret->i_sample_count )
3992         FreeAndResetChunk( ret );
3993
3994     uint32_t default_duration = 0;
3995     if( BOXDATA(p_tfhd)->i_flags & MP4_TFHD_DFLT_SAMPLE_DURATION )
3996         default_duration = BOXDATA(p_tfhd)->i_default_sample_duration;
3997
3998     uint32_t default_size = 0;
3999     if( BOXDATA(p_tfhd)->i_flags & MP4_TFHD_DFLT_SAMPLE_SIZE )
4000         default_size = BOXDATA(p_tfhd)->i_default_sample_size;
4001
4002     MP4_Box_t *p_trun = MP4_BoxGet( p_traf, "trun");
4003     if( p_trun == NULL)
4004     {
4005         msg_Warn( p_demux, "no trun box found!" );
4006         return VLC_EGENERIC;
4007     }
4008     MP4_Box_data_trun_t *p_trun_data = p_trun->data.p_trun;
4009
4010     ret->i_sample_count = p_trun_data->i_sample_count;
4011     assert( ret->i_sample_count > 0 );
4012     ret->i_sample_description_index = 1; /* seems to be always 1, is it? */
4013     ret->i_sample_first = p_track->i_sample_first;
4014     p_track->i_sample_first += ret->i_sample_count;
4015
4016     ret->i_first_dts = p_track->i_first_dts;
4017
4018     /* XXX I already saw DASH content with no default_duration and no
4019      * MP4_TRUN_SAMPLE_DURATION flag, but a sidx box was present.
4020      * This chunk of code might be buggy with segments having
4021      * more than one subsegment. */
4022     if( !default_duration )
4023     {
4024         MP4_Box_t *p_trex = MP4_GetTrexByTrackID( p_moof, i_track_ID );
4025         if ( p_trex )
4026             default_duration = BOXDATA(p_trex)->i_default_sample_duration;
4027         else if( p_sidx )
4028         {
4029             MP4_Box_data_sidx_t *p_sidx_data = BOXDATA(p_sidx);
4030             assert( p_sidx_data->i_reference_count == 1 );
4031
4032             if( p_sidx_data->i_timescale == 0 )
4033                 return VLC_EGENERIC;
4034
4035             unsigned i_chunk_duration = p_sidx_data->p_items[0].i_subsegment_duration /
4036                                         p_sidx_data->i_timescale;
4037             default_duration = i_chunk_duration * p_track->i_timescale / ret->i_sample_count;
4038
4039         }
4040     }
4041
4042     msg_Dbg( p_demux, "Default sample duration is %"PRIu32, default_duration );
4043
4044     ret->p_sample_count_dts = calloc( ret->i_sample_count, sizeof( uint32_t ) );
4045     ret->p_sample_delta_dts = calloc( ret->i_sample_count, sizeof( uint32_t ) );
4046
4047     if( !ret->p_sample_count_dts || !ret->p_sample_delta_dts )
4048         return VLC_ENOMEM;
4049
4050     ret->p_sample_count_pts = calloc( ret->i_sample_count, sizeof( uint32_t ) );
4051     if( !ret->p_sample_count_pts )
4052         return VLC_ENOMEM;
4053
4054     if( p_trun_data->i_flags & MP4_TRUN_SAMPLE_TIME_OFFSET )
4055     {
4056         ret->p_sample_offset_pts = calloc( ret->i_sample_count, sizeof( int32_t ) );
4057         if( !ret->p_sample_offset_pts )
4058             return VLC_ENOMEM;
4059     }
4060
4061     ret->p_sample_size = calloc( ret->i_sample_count, sizeof( uint32_t ) );
4062     if( !ret->p_sample_size )
4063         return VLC_ENOMEM;
4064
4065     ret->p_sample_data = calloc( ret->i_sample_count, sizeof( uint8_t * ) );
4066     if( !ret->p_sample_data )
4067         return VLC_ENOMEM;
4068
4069     uint32_t dur = 0, i_mdatlen = 0, len;
4070     uint32_t chunk_duration = 0, chunk_size = 0;
4071
4072     /* Skip header of mdat */
4073     uint8_t mdat[8];
4074     int i_read = stream_Read( p_demux->s, &mdat, 8 );
4075     i_mdatlen = GetDWBE( mdat );
4076     if ( i_read < 8 || i_mdatlen < 8 ||
4077          VLC_FOURCC( mdat[4], mdat[5], mdat[6], mdat[7] ) != ATOM_mdat )
4078         return VLC_EGENERIC;
4079
4080     for( uint32_t i = 0; i < ret->i_sample_count; i++)
4081     {
4082         if( p_trun_data->i_flags & MP4_TRUN_SAMPLE_DURATION )
4083             dur = p_trun_data->p_samples[i].i_duration;
4084         else
4085             dur = default_duration;
4086         ret->p_sample_delta_dts[i] = dur;
4087         chunk_duration += dur;
4088
4089         ret->p_sample_count_dts[i] = ret->p_sample_count_pts[i] = 1;
4090
4091         if( ret->p_sample_offset_pts )
4092         {
4093             if ( p_trun_data->i_version == 0 )
4094                 ret->p_sample_offset_pts[i] = (int32_t) p_trun_data->p_samples[i].i_composition_time_offset;
4095             else
4096                 ret->p_sample_offset_pts[i] = __MIN( INT32_MAX, p_trun_data->p_samples[i].i_composition_time_offset );
4097         }
4098
4099         if( p_trun_data->i_flags & MP4_TRUN_SAMPLE_SIZE )
4100             len = ret->p_sample_size[i] = p_trun_data->p_samples[i].i_size;
4101         else
4102             len = ret->p_sample_size[i] = default_size;
4103
4104         if ( chunk_size + len > ( i_mdatlen - 8 ) )
4105             return VLC_EGENERIC;
4106
4107         ret->p_sample_data[i] = malloc( len );
4108         if( ret->p_sample_data[i] == NULL )
4109             return VLC_ENOMEM;
4110         uint32_t i_read = stream_ReadU32( p_demux->s, ret->p_sample_data[i], len );
4111         if( i_read < len )
4112             return VLC_EGENERIC;
4113         chunk_size += len;
4114     }
4115     ret->i_last_dts = ret->i_first_dts + chunk_duration - dur;
4116     p_track->i_first_dts = chunk_duration + ret->i_first_dts;
4117
4118     if( p_track->b_codec_need_restart &&
4119             p_track->fmt.i_cat == VIDEO_ES )
4120         ReInitDecoder( p_demux, p_track );
4121
4122     /* Skip if we didn't reach the end of mdat box */
4123     if ( chunk_size < (i_mdatlen - 8) )
4124         stream_ReadU32( p_demux->s, NULL, i_mdatlen - chunk_size - 8 );
4125
4126     p_track->b_has_non_empty_cchunk = true;
4127     return VLC_SUCCESS;
4128 }
4129
4130
4131 /**
4132  * Get the next chunk of the track identified by i_tk_id.
4133  * \Note We don't want to seek all the time, so if the first chunk given by the
4134  * input method doesn't belong to the right track, we don't throw it away,
4135  * and so, in general, this function fetch more than one chunk.
4136  * Not to mention that a new init fragment might be put everywhere
4137  * between two chunks by the input method.
4138  */
4139 static int MP4_frg_GetChunks( demux_t *p_demux, const unsigned i_tk_id )
4140 {
4141     demux_sys_t *p_sys = p_demux->p_sys;
4142     mp4_track_t *p_track;
4143
4144     for( unsigned i = 0; i < p_sys->i_tracks; i++ )
4145     {
4146         MP4_Box_t *p_chunk = MP4_BoxGetNextChunk( p_demux->s );
4147         if( !p_chunk )
4148             return VLC_EGENERIC;
4149
4150         if( !p_chunk->p_first )
4151             goto MP4_frg_GetChunks_Error;
4152         uint32_t i_type = p_chunk->p_first->i_type;
4153         uint32_t tid = 0;
4154         if( i_type == ATOM_uuid || i_type == ATOM_ftyp )
4155         {
4156             MP4_BoxFree( p_demux->s, p_sys->p_root );
4157             p_sys->p_root = p_chunk;
4158
4159             if( i_type == ATOM_ftyp ) /* DASH */
4160             {
4161                 MP4_Box_t *p_tkhd = MP4_BoxGet( p_chunk, "/moov/trak[0]/tkhd" );
4162                 if( !p_tkhd )
4163                 {
4164                     msg_Warn( p_demux, "No tkhd found!" );
4165                     goto MP4_frg_GetChunks_Error;
4166                 }
4167                 tid = p_tkhd->data.p_tkhd->i_track_ID;
4168             }
4169             else                      /* Smooth Streaming */
4170             {
4171                 assert( !CmpUUID( &p_chunk->p_first->i_uuid, &SmooBoxUUID ) );
4172                 MP4_Box_t *p_stra = MP4_BoxGet( p_chunk, "/uuid/uuid[0]" );
4173                 if( !p_stra || CmpUUID( &p_stra->i_uuid, &StraBoxUUID ) )
4174                 {
4175                     msg_Warn( p_demux, "No StraBox found!" );
4176                     goto MP4_frg_GetChunks_Error;
4177                 }
4178                 tid = p_stra->data.p_stra->i_track_ID;
4179             }
4180
4181             p_track = MP4_frg_GetTrackByID( p_demux, tid );
4182             if( !p_track )
4183                 goto MP4_frg_GetChunks_Error;
4184             p_track->b_codec_need_restart = true;
4185
4186             return MP4_frg_GetChunks( p_demux, i_tk_id );
4187         }
4188
4189         if( MP4_frg_GetChunk( p_demux, p_chunk, &tid ) != VLC_SUCCESS )
4190             goto MP4_frg_GetChunks_Error;
4191
4192         MP4_BoxFree( p_demux->s, p_chunk );
4193
4194         if( tid == i_tk_id )
4195             break;
4196         else
4197             continue;
4198
4199 MP4_frg_GetChunks_Error:
4200         MP4_BoxFree( p_demux->s, p_chunk );
4201         return VLC_EGENERIC;
4202     }
4203
4204     return VLC_SUCCESS;
4205 }
4206
4207 static int MP4_frg_TrackSelect( demux_t *p_demux, mp4_track_t *p_track )
4208 {
4209     if( !p_track->b_ok || p_track->b_chapter )
4210     {
4211         return VLC_EGENERIC;
4212     }
4213
4214     if( p_track->b_selected )
4215     {
4216         msg_Warn( p_demux, "track[Id 0x%x] already selected", p_track->i_track_ID );
4217         return VLC_SUCCESS;
4218     }
4219
4220     msg_Dbg( p_demux, "Select track id %u", p_track->i_track_ID );
4221     p_track->b_selected = true;
4222     return VLC_SUCCESS;
4223 }
4224
4225 /**
4226  * DemuxFrg: read packet and send them to decoders
4227  * \return 1 on success, 0 on error.
4228  * TODO check for newly selected track
4229  */
4230 int DemuxFrg( demux_t *p_demux )
4231 {
4232     demux_sys_t *p_sys = p_demux->p_sys;
4233     unsigned i_track;
4234     unsigned i_track_selected;
4235
4236     /* check for newly selected/unselected track */
4237     for( i_track = 0, i_track_selected = 0; i_track < p_sys->i_tracks; i_track++ )
4238     {
4239         mp4_track_t *tk = &p_sys->track[i_track];
4240         bool b;
4241
4242         if( !tk->b_ok || tk->b_chapter )
4243             continue;
4244
4245         es_out_Control( p_demux->out, ES_OUT_GET_ES_STATE, tk->p_es, &b );
4246         msg_Dbg( p_demux, "track %u %s!", tk->i_track_ID, b ? "enabled" : "disabled" );
4247
4248         if( tk->b_selected && !b )
4249         {
4250             MP4_TrackUnselect( p_demux, tk );
4251         }
4252         else if( !tk->b_selected && b)
4253         {
4254             MP4_frg_TrackSelect( p_demux, tk );
4255         }
4256
4257         if( tk->b_selected )
4258             i_track_selected++;
4259     }
4260
4261     if( i_track_selected <= 0 )
4262     {
4263         p_sys->i_time += __MAX( p_sys->i_timescale / 10 , 1 );
4264         if( p_sys->i_timescale > 0 )
4265         {
4266             int64_t i_length = CLOCK_FREQ *
4267                                (mtime_t)p_sys->moovfragment.i_duration /
4268                                (mtime_t)p_sys->i_timescale;
4269             if( MP4_GetMoviePTS( p_sys ) >= i_length )
4270                 return 0;
4271             return 1;
4272         }
4273
4274         msg_Warn( p_demux, "no track selected, exiting..." );
4275         return 0;
4276     }
4277
4278     /* first wait for the good time to read a packet */
4279     es_out_Control( p_demux->out, ES_OUT_SET_PCR, VLC_TS_0 + p_sys->i_pcr );
4280
4281     p_sys->i_pcr = MP4_GetMoviePTS( p_sys );
4282
4283     /* we will read 100ms for each stream so ...*/
4284     p_sys->i_time += __MAX( p_sys->i_timescale / 10, 1 );
4285
4286     for( i_track = 0; i_track < p_sys->i_tracks; i_track++ )
4287     {
4288         mp4_track_t *tk = &p_sys->track[i_track];
4289
4290         if( !tk->b_ok || tk->b_chapter || !tk->b_selected )
4291         {
4292             msg_Warn( p_demux, "Skipping track id %u", tk->i_track_ID );
4293             continue;
4294         }
4295
4296         if( !tk->b_has_non_empty_cchunk )
4297         {
4298             if( MP4_frg_GetChunks( p_demux, tk->i_track_ID ) != VLC_SUCCESS )
4299             {
4300                 msg_Info( p_demux, "MP4_frg_GetChunks returned error. End of stream?" );
4301                 return 0;
4302             }
4303         }
4304
4305         while( MP4_TrackGetDTS( p_demux, tk ) < MP4_GetMoviePTS( p_sys ) )
4306         {
4307             block_t *p_block;
4308             int64_t i_delta;
4309
4310             mp4_chunk_t *ck = tk->cchunk;
4311             if( ck->i_sample >= ck->i_sample_count )
4312             {
4313                 msg_Err( p_demux, "sample %"PRIu32" of %"PRIu32"",
4314                                     ck->i_sample, ck->i_sample_count );
4315                 return 0;
4316             }
4317
4318             uint32_t sample_size = ck->p_sample_size[ck->i_sample];
4319             p_block = block_Alloc( sample_size );
4320             uint8_t *src = ck->p_sample_data[ck->i_sample];
4321             memcpy( p_block->p_buffer, src, sample_size );
4322
4323             ck->i_sample++;
4324             if( ck->i_sample == ck->i_sample_count )
4325                 tk->b_has_non_empty_cchunk = false;
4326
4327             /* dts */
4328             p_block->i_dts = VLC_TS_0 + MP4_TrackGetDTS( p_demux, tk );
4329             /* pts */
4330             i_delta = MP4_TrackGetPTSDelta( p_demux, tk );
4331             if( i_delta != -1 )
4332                 p_block->i_pts = p_block->i_dts + i_delta;
4333             else if( tk->fmt.i_cat != VIDEO_ES )
4334                 p_block->i_pts = p_block->i_dts;
4335             else
4336                 p_block->i_pts = VLC_TS_INVALID;
4337
4338             es_out_Send( p_demux->out, tk->p_es, p_block );
4339
4340             tk->i_sample++;
4341
4342             if( !tk->b_has_non_empty_cchunk )
4343                 break;
4344         }
4345     }
4346     return 1;
4347 }
4348
4349 static MP4_Box_t * LoadNextChunk( demux_t *p_demux )
4350 {
4351     /* Read Next Chunk */
4352     MP4_Box_t *p_chunk = MP4_BoxGetNextChunk( p_demux->s );
4353     if( !p_chunk )
4354     {
4355         msg_Warn( p_demux, "no next chunk" );
4356         return NULL;
4357     }
4358
4359     if( !p_chunk->p_first )
4360     {
4361         msg_Warn( p_demux, "no next chunk child" );
4362         return NULL;
4363     }
4364
4365     return p_chunk;
4366 }
4367
4368 static bool BoxExistsInRootTree( MP4_Box_t *p_root, uint32_t i_type, off_t i_pos )
4369 {
4370     while ( p_root )
4371     {
4372         if ( p_root->i_pos == i_pos )
4373         {
4374             assert( i_type == p_root->i_type );
4375             break;
4376         }
4377         p_root = p_root->p_next;
4378     }
4379     return (p_root != NULL);
4380 }
4381
4382 /* Keeps an ordered chain of all fragments */
4383 static bool AddFragment( demux_t *p_demux, MP4_Box_t *p_moox )
4384 {
4385     demux_sys_t *p_sys = p_demux->p_sys;
4386     mp4_fragment_t *p_base_fragment = & p_sys->moovfragment;
4387     if ( !p_moox )
4388         return false;
4389
4390     if( p_moox->i_type == ATOM_moov )
4391     {
4392         if ( !p_sys->moovfragment.p_moox )
4393         {
4394             p_sys->moovfragment.p_moox = p_moox;
4395             MP4_Box_t *p_mvhd;
4396             if( (p_mvhd = MP4_BoxGet( p_moox, "mvhd" )) )
4397             {
4398                 p_sys->i_timescale = BOXDATA(p_mvhd)->i_timescale;
4399                 p_sys->i_overall_duration = BOXDATA(p_mvhd)->i_duration;
4400             }
4401
4402             if ( MP4_BoxCount( p_moox, "mvex" ) || !p_mvhd )
4403             { /* duration might be wrong an be set to whole duration :/ */
4404                p_sys->moovfragment.i_duration = 0;
4405                MP4_Box_t *p_tkhd;
4406                MP4_Box_t *p_trak = MP4_BoxGet( p_moox, "trak" );
4407                while( p_trak )
4408                {
4409                    if ( p_trak->i_type == ATOM_trak && (p_tkhd = MP4_BoxGet( p_trak, "tkhd" )) )
4410                    {
4411                        if ( BOXDATA(p_tkhd)->i_duration > p_sys->moovfragment.i_duration )
4412                            p_sys->moovfragment.i_duration = BOXDATA(p_tkhd)->i_duration;
4413                    }
4414                    p_trak = p_trak->p_next;
4415                }
4416             }
4417
4418             msg_Dbg( p_demux, "added fragment %4.4s", (char*) &p_moox->i_type );
4419             return true;
4420         }
4421         return false;
4422     }
4423     else // p_moox->i_type == ATOM_moof
4424     {
4425         assert(p_moox->i_type == ATOM_moof);
4426         mp4_fragment_t *p_fragment = p_sys->moovfragment.p_next;
4427         while ( p_fragment )
4428         {
4429             if ( !p_base_fragment->p_moox || p_moox->i_pos > p_base_fragment->p_moox->i_pos )
4430             {
4431                 p_base_fragment = p_fragment;
4432                 p_fragment = p_fragment->p_next;
4433             }
4434             else if ( p_moox->i_pos == p_base_fragment->p_moox->i_pos )
4435             {
4436                 /* already exists */
4437                 return false;
4438             }
4439         }
4440     }
4441
4442     /* Add the moof fragment */
4443     mp4_fragment_t *p_new = malloc(sizeof(mp4_fragment_t));
4444     if ( !p_new ) return false;
4445     p_new->p_moox = p_moox;
4446     p_new->i_duration = 0;
4447     p_new->p_next = p_base_fragment->p_next;
4448     p_base_fragment->p_next = p_new;
4449     msg_Dbg( p_demux, "added fragment %4.4s", (char*) &p_moox->i_type );
4450
4451     /* we have to probe all fragments :/ */
4452     uint64_t i_traf_base_data_offset = 0;
4453     uint64_t i_traf_min_offset = 0;
4454     uint32_t i_traf = 0;
4455     uint32_t i_traf_total_size = 0;
4456     uint32_t i_trafs_total_size = 0;
4457
4458     MP4_Box_t *p_traf = MP4_BoxGet( p_new->p_moox, "traf" );
4459     while ( p_traf )
4460     {
4461         if ( p_traf->i_type != ATOM_traf )
4462         {
4463            p_traf = p_traf->p_next;
4464            continue;
4465         }
4466         const MP4_Box_t *p_tfhd = MP4_BoxGet( p_traf, "tfhd" );
4467         const MP4_Box_t *p_trun = MP4_BoxGet( p_traf, "trun" );
4468         if ( !p_tfhd || !p_trun )
4469         {
4470            p_traf = p_traf->p_next;
4471            continue;
4472         }
4473
4474         uint32_t i_track_timescale = 0;
4475         uint32_t i_track_defaultsamplesize = 0;
4476         uint32_t i_track_defaultsampleduration = 0;
4477         if ( p_sys->b_smooth )
4478         {
4479             /* stra sets identical timescales */
4480             i_track_timescale = p_sys->i_timescale;
4481             i_track_defaultsamplesize = 1;
4482             i_track_defaultsampleduration = 1;
4483         }
4484         else
4485         {
4486             /* set trex for defaults */
4487              MP4_Box_t *p_trex = MP4_GetTrexByTrackID( p_sys->moovfragment.p_moox, BOXDATA(p_tfhd)->i_track_ID );
4488              if ( p_trex )
4489              {
4490                 i_track_defaultsamplesize = BOXDATA(p_trex)->i_default_sample_size;
4491                 i_track_defaultsampleduration = BOXDATA(p_trex)->i_default_sample_duration;
4492              }
4493
4494              MP4_Box_t *p_trak = MP4_GetTrakByTrackID( p_sys->moovfragment.p_moox, BOXDATA(p_tfhd)->i_track_ID );
4495              if ( p_trak )
4496              {
4497                 MP4_Box_t *p_mdhd = MP4_BoxGet( p_trak, "mdia/mdhd" );
4498                 if ( p_mdhd ) i_track_timescale = BOXDATA(p_mdhd)->i_timescale;
4499              }
4500         }
4501
4502         if ( !i_track_timescale )
4503         {
4504            p_traf = p_traf->p_next;
4505            continue;
4506         }
4507
4508         if ( BOXDATA(p_tfhd)->i_flags & MP4_TFHD_BASE_DATA_OFFSET )
4509         {
4510             i_traf_base_data_offset = BOXDATA(p_tfhd)->i_base_data_offset;
4511         }
4512         else if ( BOXDATA(p_tfhd)->i_flags & MP4_TFHD_DEFAULT_BASE_IS_MOOF )
4513         {
4514             i_traf_base_data_offset = p_new->p_moox->i_pos + 8;
4515         }
4516         else
4517         {
4518             if ( i_traf == 0 )
4519                 i_traf_base_data_offset = p_new->p_moox->i_pos /*+ 8*/;
4520             else
4521                 i_traf_base_data_offset += i_traf_total_size;
4522         }
4523
4524         i_traf_total_size = 0;
4525
4526         uint64_t i_trun_data_offset = i_traf_base_data_offset;
4527         uint64_t i_traf_duration = 0;
4528         uint32_t i_trun_size = 0;
4529         while ( p_trun && p_tfhd )
4530         {
4531             if ( p_trun->i_type != ATOM_trun )
4532             {
4533                p_trun = p_trun->p_next;
4534                continue;
4535             }
4536             const MP4_Box_data_trun_t *p_trundata = p_trun->data.p_trun;
4537
4538             /* Get data offset */
4539             if ( p_trundata->i_flags & MP4_TRUN_DATA_OFFSET )
4540                 i_trun_data_offset += __MAX( p_trundata->i_data_offset, 0 );
4541             else
4542                 i_trun_data_offset += i_trun_size;
4543
4544             i_trun_size = 0;
4545
4546             /* Sum total time */
4547             if ( p_trundata->i_flags & MP4_TRUN_SAMPLE_DURATION )
4548             {
4549                 for( uint32_t i=0; i< p_trundata->i_sample_count; i++ )
4550                     i_traf_duration += p_trundata->p_samples[i].i_duration;
4551             }
4552             else if ( BOXDATA(p_tfhd)->i_flags & MP4_TFHD_DFLT_SAMPLE_DURATION )
4553             {
4554                 i_traf_duration += p_trundata->i_sample_count *
4555                         BOXDATA(p_tfhd)->i_default_sample_duration;
4556             }
4557             else
4558             {
4559                 i_traf_duration += p_trundata->i_sample_count *
4560                         i_track_defaultsampleduration;
4561             }
4562
4563             /* Get total traf size */
4564             if ( p_trundata->i_flags & MP4_TRUN_SAMPLE_SIZE )
4565             {
4566                 for( uint32_t i=0; i< p_trundata->i_sample_count; i++ )
4567                     i_trun_size += p_trundata->p_samples[i].i_size;
4568             }
4569             else if ( BOXDATA(p_tfhd)->i_flags & MP4_TFHD_DFLT_SAMPLE_SIZE )
4570             {
4571                 i_trun_size += p_trundata->i_sample_count *
4572                         BOXDATA(p_tfhd)->i_default_sample_size;
4573             }
4574             else
4575             {
4576                 i_trun_size += p_trundata->i_sample_count *
4577                         i_track_defaultsamplesize;
4578             }
4579
4580             i_traf_total_size += i_trun_size;
4581
4582             if ( i_traf_min_offset )
4583                 i_traf_min_offset = __MIN( i_trun_data_offset, i_traf_min_offset );
4584             else
4585                 i_traf_min_offset = i_trun_data_offset;
4586
4587             p_trun = p_trun->p_next;
4588         }
4589
4590         i_trafs_total_size += i_traf_total_size;
4591         p_new->i_duration = __MAX( p_new->i_duration, i_traf_duration * p_sys->i_timescale / i_track_timescale );
4592
4593         p_traf = p_traf->p_next;
4594         i_traf++;
4595     }
4596
4597     p_new->i_chunk_range_min_offset = i_traf_min_offset;
4598     p_new->i_chunk_range_max_offset = i_traf_min_offset + i_trafs_total_size;
4599
4600     msg_Dbg( p_demux, "new fragment is %"PRId64" %"PRId64, p_new->i_chunk_range_min_offset, p_new->i_chunk_range_max_offset );
4601
4602     /* compute total duration with that new fragment if no overall provided */
4603     MP4_Box_t *p_mehd = MP4_BoxGet( p_sys->moovfragment.p_moox, "mvex/mehd");
4604     if ( !p_mehd )
4605     {
4606         p_sys->i_overall_duration = 0;
4607         if ( p_sys->b_fragments_probed )
4608         {
4609             p_new = &p_sys->moovfragment;
4610             while ( p_new )
4611             {
4612                 p_sys->i_overall_duration += p_new->i_duration;
4613                 p_new = p_new->p_next;
4614             }
4615         }
4616     }
4617     else
4618         p_sys->i_overall_duration = BOXDATA(p_mehd)->i_fragment_duration;
4619
4620     msg_Dbg( p_demux, "total fragments duration %"PRId64, CLOCK_FREQ * p_sys->i_overall_duration / p_sys->i_timescale);
4621     return true;
4622 }
4623
4624 #define MP4_MFRO_BOXSIZE 16
4625 static int ProbeIndex( demux_t *p_demux )
4626 {
4627     demux_sys_t *p_sys = p_demux->p_sys;
4628     uint64_t i_backup_pos, i_stream_size;
4629     uint8_t mfro[MP4_MFRO_BOXSIZE];
4630     assert( p_sys->b_seekable );
4631
4632     if ( MP4_BoxCount( p_sys->p_root, "/mfra" ) )
4633         return VLC_SUCCESS;
4634
4635     i_stream_size = stream_Size( p_demux->s );
4636     if ( ( i_stream_size >> 62 ) ||
4637          ( i_stream_size < MP4_MFRO_BOXSIZE ) ||
4638          ( !MP4_stream_Tell( p_demux->s, &i_backup_pos ) ) ||
4639          ( stream_Seek( p_demux->s, i_stream_size - MP4_MFRO_BOXSIZE ) != VLC_SUCCESS )
4640        )
4641     {
4642         msg_Dbg( p_demux, "Probing tail for mfro has failed" );
4643         return VLC_EGENERIC;
4644     }
4645
4646     if ( stream_Read( p_demux->s, &mfro, MP4_MFRO_BOXSIZE ) == MP4_MFRO_BOXSIZE &&
4647          VLC_FOURCC(mfro[4],mfro[5],mfro[6],mfro[7]) == ATOM_mfro &&
4648          GetDWBE( &mfro ) == MP4_MFRO_BOXSIZE )
4649     {
4650         uint32_t i_offset = GetDWBE( &mfro[12] );
4651         msg_Dbg( p_demux, "will read mfra index at %"PRIu64, i_stream_size - i_offset );
4652         if ( i_stream_size > i_offset &&
4653              stream_Seek( p_demux->s, i_stream_size - i_offset ) == VLC_SUCCESS )
4654         {
4655             msg_Dbg( p_demux, "reading mfra index at %"PRIu64, i_stream_size - i_offset );
4656             MP4_ReadBoxContainerChildren( p_demux->s, p_sys->p_root, ATOM_mfra );
4657         }
4658     }
4659
4660     return stream_Seek( p_demux->s, i_backup_pos );
4661 }
4662 #undef MP4_MFRO_BOXSIZE
4663
4664 static int ProbeFragments( demux_t *p_demux, bool b_force )
4665 {
4666     demux_sys_t *p_sys = p_demux->p_sys;
4667     uint64_t i_current_pos;
4668
4669     if ( MP4_stream_Tell( p_demux->s, &i_current_pos ) )
4670         msg_Dbg( p_demux, "probing fragments from %"PRId64, i_current_pos );
4671
4672     assert( p_sys->p_root );
4673
4674     if ( p_sys->b_fastseekable || b_force )
4675     {
4676         MP4_ReadBoxContainerChildren( p_demux->s, p_sys->p_root, 0 ); /* Get the rest of the file */
4677         p_sys->b_fragments_probed = true;
4678     }
4679     else
4680     {
4681         /* We stop at first moof, which validates our fragmentation condition
4682          * and we'll find others while reading. */
4683         MP4_ReadBoxContainerChildren( p_demux->s, p_sys->p_root, ATOM_moof );
4684     }
4685
4686     if ( !p_sys->moovfragment.p_moox )
4687     {
4688         MP4_Box_t *p_moov = MP4_BoxGet( p_sys->p_root, "/moov" );
4689         if ( !p_moov )
4690         {
4691             /* moov/mvex before probing should be present anyway */
4692             MP4_BoxDumpStructure( p_demux->s, p_sys->p_root );
4693             return VLC_EGENERIC;
4694         }
4695         AddFragment( p_demux, p_moov );
4696     }
4697
4698     MP4_Box_t *p_moof = MP4_BoxGet( p_sys->p_root, "moof" );
4699     while ( p_moof )
4700     {
4701         if ( p_moof->i_type == ATOM_moof )
4702             AddFragment( p_demux, p_moof );
4703         p_moof = p_moof->p_next;
4704     }
4705
4706     MP4_Box_t *p_mdat = MP4_BoxGet( p_sys->p_root, "mdat" );
4707     if ( p_mdat )
4708     {
4709         stream_Seek( p_demux->s, p_mdat->i_pos );
4710         msg_Dbg( p_demux, "rewinding to mdat %"PRId64, p_mdat->i_pos );
4711     }
4712
4713     return VLC_SUCCESS;
4714 }
4715
4716 static mp4_fragment_t * GetFragmentByPos( demux_t *p_demux, uint64_t i_pos, bool b_exact )
4717 {
4718     mp4_fragment_t *p_fragment = &p_demux->p_sys->moovfragment;
4719     while ( p_fragment )
4720     {
4721         if ( i_pos <= p_fragment->i_chunk_range_max_offset &&
4722              ( !b_exact || i_pos >= p_fragment->i_chunk_range_min_offset ) )
4723         {
4724             msg_Dbg( p_demux, "fragment matched %"PRIu64" << %"PRIu64" << %"PRIu64,
4725                      p_fragment->i_chunk_range_min_offset, i_pos,
4726                      p_fragment->i_chunk_range_max_offset );
4727             return p_fragment;
4728         }
4729         else
4730         {
4731             p_fragment = p_fragment->p_next;
4732         }
4733     }
4734     return NULL;
4735 }
4736
4737 /* Get a matching fragment data start by clock time */
4738 static mp4_fragment_t * GetFragmentByTime( demux_t *p_demux, const mtime_t i_time )
4739 {
4740     mp4_fragment_t *p_fragment = &p_demux->p_sys->moovfragment;
4741     mtime_t i_base_time = 0;
4742     while ( p_fragment )
4743     {
4744         mtime_t i_length = CLOCK_FREQ * p_fragment->i_duration / p_demux->p_sys->i_timescale;
4745         if ( i_time >= i_base_time &&
4746              i_time <= i_base_time + i_length )
4747         {
4748             return p_fragment;
4749         }
4750         else
4751         {
4752             i_base_time += i_length;
4753             p_fragment = p_fragment->p_next;
4754         }
4755
4756         if ( !p_demux->p_sys->b_fragments_probed )
4757             return NULL; /* We have no way to guess missing fragments time */
4758     }
4759     return NULL;
4760 }
4761
4762 /* Returns fragment scaled time offset */
4763 static mtime_t LeafGetFragmentTimeOffset( demux_t *p_demux, mp4_fragment_t *p_fragment )
4764 {
4765     mtime_t i_base_scaledtime = 0;
4766     mp4_fragment_t *p_current = &p_demux->p_sys->moovfragment;
4767     while ( p_current != p_fragment )
4768     {
4769         i_base_scaledtime += p_current->i_duration;
4770         p_current = p_current->p_next;
4771     }
4772     return i_base_scaledtime;
4773 }
4774
4775 static int LeafParseTRUN( demux_t *p_demux, mp4_track_t *p_track,
4776                       const uint32_t i_defaultduration, const uint32_t i_defaultsize,
4777                       const MP4_Box_data_trun_t *p_trun, uint32_t * const pi_mdatlen )
4778 {
4779     assert( p_trun->i_sample_count );
4780     msg_Dbg( p_demux, "Default sample duration %"PRIu32" size %"PRIu32" firstdts %"PRIu64,
4781              i_defaultduration, i_defaultsize, p_track->i_first_dts );
4782
4783     uint32_t dur = 0, len;
4784     uint32_t chunk_size = 0;
4785     mtime_t i_nzdts = CLOCK_FREQ * p_track->i_time / p_track->i_timescale;
4786
4787     mtime_t i_nzpts;
4788
4789     for( uint32_t i = 0; i < p_trun->i_sample_count; i++)
4790     {
4791         i_nzdts += CLOCK_FREQ * dur / p_track->i_timescale;
4792         i_nzpts = i_nzdts;
4793
4794         if( p_trun->i_flags & MP4_TRUN_SAMPLE_DURATION )
4795             dur = p_trun->p_samples[i].i_duration;
4796         else
4797             dur = i_defaultduration;
4798
4799         p_track->i_time += dur;
4800
4801         if( p_trun->i_flags & MP4_TRUN_SAMPLE_TIME_OFFSET )
4802         {
4803             if ( p_trun->i_version == 0 )
4804                 i_nzpts += CLOCK_FREQ * (int32_t) p_trun->p_samples[i].i_composition_time_offset / p_track->i_timescale;
4805             else
4806                 i_nzpts += CLOCK_FREQ * p_trun->p_samples[i].i_composition_time_offset / p_track->i_timescale;
4807         }
4808
4809         if( p_trun->i_flags & MP4_TRUN_SAMPLE_SIZE )
4810             len = p_trun->p_samples[i].i_size;
4811         else
4812             len = i_defaultsize;
4813
4814         assert( dur ); /* dur, dur ! */
4815         assert( len );
4816
4817         if ( chunk_size + len > *pi_mdatlen )
4818         {
4819             /* update data left in mdat */
4820             *pi_mdatlen -= chunk_size;
4821             return VLC_EGENERIC;
4822         }
4823
4824         block_t *p_block = stream_Block( p_demux->s, __MIN( len, INT32_MAX ) );
4825         uint32_t i_read = ( p_block ) ? p_block->i_buffer : 0;
4826         if( i_read < len )
4827         {
4828             /* update data left in mdat */
4829             *pi_mdatlen -= chunk_size;
4830             *pi_mdatlen -= i_read;
4831             free( p_block );
4832             return VLC_EGENERIC;
4833         }
4834
4835         if ( p_demux->p_sys->i_pcr < VLC_TS_0 )
4836         {
4837             p_demux->p_sys->i_pcr = i_nzdts;
4838             es_out_Control( p_demux->out, ES_OUT_SET_PCR, VLC_TS_0 + i_nzdts );
4839         }
4840
4841         if ( p_track->p_es )
4842         {
4843             p_block->i_dts = VLC_TS_0 + i_nzdts;
4844             p_block->i_pts = VLC_TS_0 + i_nzpts;
4845             es_out_Send( p_demux->out, p_track->p_es, p_block );
4846         }
4847         else free( p_block );
4848
4849         chunk_size += len;
4850     }
4851
4852     /* update data left in mdat */
4853     *pi_mdatlen -= chunk_size;
4854     return VLC_SUCCESS;
4855 }
4856
4857 static int LeafGetTrackAndChunkByMOOVPos( demux_t *p_demux, uint64_t *pi_pos,
4858                                       mp4_track_t **pp_tk, unsigned int *pi_chunk )
4859 {
4860     const demux_sys_t *p_sys = p_demux->p_sys;
4861
4862     mp4_track_t *p_tk_closest = NULL;
4863     uint64_t i_closest = UINT64_MAX;
4864     unsigned int i_chunk_closest;
4865
4866     *pp_tk = NULL;
4867
4868     for ( unsigned int i_track = 0; i_track < p_sys->i_tracks; i_track++ )
4869     {
4870         for( unsigned int i_chunk = 0; i_chunk < p_sys->track[i_track].i_chunk_count; i_chunk++ )
4871         {
4872             if ( p_sys->track[i_track].chunk[i_chunk].i_offset > *pi_pos )
4873             {
4874                 i_closest = __MIN( i_closest, p_sys->track[i_track].chunk[i_chunk].i_offset );
4875                 p_tk_closest = &p_sys->track[i_track];
4876                 i_chunk_closest = i_chunk;
4877             }
4878
4879             if ( *pi_pos == p_sys->track[i_track].chunk[i_chunk].i_offset )
4880             {
4881                 *pp_tk = &p_sys->track[i_track];
4882                 *pi_chunk = i_chunk;
4883                 return VLC_SUCCESS;
4884             }
4885         }
4886     }
4887
4888     if ( i_closest != UINT64_MAX )
4889     {
4890         *pi_pos = i_closest;
4891         *pp_tk = p_tk_closest;
4892         *pi_chunk = i_chunk_closest;
4893         return VLC_ENOOBJ;
4894     }
4895     else return VLC_EGENERIC;
4896 }
4897
4898 static int LeafMOOVGetSamplesSize( const mp4_track_t *p_track, const uint32_t i_sample,
4899                            uint32_t *pi_samplestoread, uint32_t *pi_samplessize,
4900                            const uint32_t i_maxbytes, const uint32_t i_maxsamples )
4901 {
4902     MP4_Box_t *p_stsz = MP4_BoxGet( p_track->p_stbl, "stsz" );
4903     if ( !p_stsz )
4904         return VLC_EGENERIC;
4905
4906     if ( BOXDATA(p_stsz)->i_sample_size == 0 )
4907     {
4908         uint32_t i_entry = i_sample;
4909         uint32_t i_totalbytes = 0;
4910         *pi_samplestoread = 1;
4911
4912         if ( i_sample >= BOXDATA(p_stsz)->i_sample_count )
4913             return VLC_EGENERIC;
4914
4915         *pi_samplessize = BOXDATA(p_stsz)->i_entry_size[i_sample];
4916         i_totalbytes += *pi_samplessize;
4917
4918         if ( *pi_samplessize > i_maxbytes )
4919             return VLC_EGENERIC;
4920
4921         i_entry++;
4922         while( i_entry < BOXDATA(p_stsz)->i_sample_count &&
4923                *pi_samplessize == BOXDATA(p_stsz)->i_entry_size[i_entry] &&
4924                i_totalbytes + *pi_samplessize < i_maxbytes &&
4925                *pi_samplestoread < i_maxsamples
4926               )
4927         {
4928             i_totalbytes += *pi_samplessize;
4929             (*pi_samplestoread)++;
4930         }
4931
4932         *pi_samplessize = i_totalbytes;
4933     }
4934     else
4935     {
4936         /* all samples have same size */
4937         *pi_samplessize = BOXDATA(p_stsz)->i_sample_size;
4938         *pi_samplestoread = __MIN( i_maxsamples, BOXDATA(p_stsz)->i_sample_count );
4939         *pi_samplestoread = __MIN( i_maxbytes / *pi_samplessize, *pi_samplestoread );
4940         *pi_samplessize = *pi_samplessize * *pi_samplestoread;
4941     }
4942
4943     return VLC_SUCCESS;
4944 }
4945
4946 static inline mtime_t LeafGetMOOVTimeInChunk( const mp4_chunk_t *p_chunk, uint32_t i_sample )
4947 {
4948     mtime_t i_time = 0;
4949     uint32_t i_index = 0;
4950
4951     while( i_sample > 0 )
4952     {
4953         if( i_sample > p_chunk->p_sample_count_dts[i_index] )
4954         {
4955             i_time += p_chunk->p_sample_count_dts[i_index] *
4956                 p_chunk->p_sample_delta_dts[i_index];
4957             i_sample -= p_chunk->p_sample_count_dts[i_index];
4958             i_index++;
4959         }
4960         else
4961         {
4962             i_time += i_sample * p_chunk->p_sample_delta_dts[i_index];
4963             break;
4964         }
4965     }
4966
4967     return i_time;
4968 }
4969
4970 static int LeafParseMDATwithMOOV( demux_t *p_demux )
4971 {
4972     demux_sys_t *p_sys = p_demux->p_sys;
4973
4974     assert( p_sys->context.i_current_box_type == ATOM_mdat );
4975     assert( p_sys->context.p_fragment->p_moox->i_type == ATOM_moov );
4976
4977     uint64_t i_current_pos;
4978     if ( !MP4_stream_Tell( p_demux->s, &i_current_pos ) )
4979         return VLC_EGENERIC;
4980
4981     if ( p_sys->context.i_mdatbytesleft == 0 ) /* Start parsing new mdat */
4982     {
4983         /* Ready mdat section */
4984         uint8_t mdat[8];
4985         int i_read = stream_Read( p_demux->s, &mdat, 8 );
4986         p_sys->context.i_mdatbytesleft = GetDWBE( mdat );
4987         if ( i_read < 8 || p_sys->context.i_mdatbytesleft < 8 ||
4988              VLC_FOURCC( mdat[4], mdat[5], mdat[6], mdat[7] ) != ATOM_mdat )
4989         {
4990             uint64_t i_pos;
4991             if ( !MP4_stream_Tell( p_demux->s, &i_pos ) )
4992                 msg_Err( p_demux, "No mdat atom at %"PRIu64, i_pos - __MAX( 0, i_read ) );
4993             return VLC_EGENERIC;
4994         }
4995         i_current_pos += 8;
4996         p_sys->context.i_mdatbytesleft -= 8;
4997     }
4998
4999     while( p_sys->context.i_mdatbytesleft > 0 )
5000     {
5001         mp4_track_t *p_track;
5002         unsigned int i_chunk;
5003
5004         /**/
5005         uint64_t i_pos = i_current_pos;
5006         int i_ret = LeafGetTrackAndChunkByMOOVPos( p_demux, &i_pos, &p_track, &i_chunk );
5007         if ( i_ret == VLC_EGENERIC )
5008         {
5009             msg_Err(p_demux, "can't find referenced chunk for start at %"PRIu64, i_current_pos );
5010             goto error;
5011         }
5012         else if( i_ret == VLC_ENOOBJ )
5013         {
5014             assert( i_pos - i_current_pos > p_sys->context.i_mdatbytesleft );
5015             int i_read = stream_Read( p_demux->s, NULL, i_pos - i_current_pos );
5016             i_current_pos += i_read;
5017             p_sys->context.i_mdatbytesleft -= i_read;
5018             if ( i_read == 0 ) goto error;
5019             continue;
5020         }
5021         /**/
5022
5023         mp4_chunk_t *p_chunk = &p_track->chunk[i_chunk];
5024
5025         uint32_t i_nb_samples_at_chunk_start = p_chunk->i_sample_first;
5026         uint32_t i_nb_samples_in_chunk = p_chunk->i_sample_count;
5027
5028         assert(i_nb_samples_in_chunk);
5029
5030         uint32_t i_nb_samples = 0;
5031         while ( i_nb_samples < i_nb_samples_in_chunk )
5032         {
5033             uint32_t i_samplessize = 0;
5034             uint32_t i_samplescounttoread = 0;
5035             i_ret = LeafMOOVGetSamplesSize( p_track,
5036                             i_nb_samples_at_chunk_start + i_nb_samples,
5037                             &i_samplescounttoread, &i_samplessize,
5038                             p_sys->context.i_mdatbytesleft,
5039                             /*i_nb_samples_in_chunk - i_nb_samples*/ 1 );
5040             if ( i_ret != VLC_SUCCESS )
5041                 goto error;
5042
5043             if( p_sys->context.i_mdatbytesleft &&
5044                 p_sys->context.i_mdatbytesleft  >= i_samplessize )
5045             {
5046                 block_t *p_block;
5047
5048                 /* now read pes */
5049
5050                 if( !(p_block = stream_Block( p_demux->s, i_samplessize )) )
5051                 {
5052                     uint64_t i_pos;
5053                     if ( MP4_stream_Tell( p_demux->s, &i_pos ) )
5054                     {
5055                         p_sys->context.i_mdatbytesleft -= ( i_pos - i_current_pos );
5056                         msg_Err( p_demux, "stream block error %"PRId64" %"PRId64, i_pos, i_pos - i_current_pos );
5057                     }
5058                     goto error;
5059                 }
5060                 else if( p_track->fmt.i_cat == SPU_ES )
5061                 {
5062                     if ( p_track->fmt.i_codec != VLC_CODEC_TX3G &&
5063                          p_track->fmt.i_codec != VLC_CODEC_SPU )
5064                         p_block->i_buffer = 0;
5065                 }
5066
5067                 i_nb_samples += i_samplescounttoread;
5068                 i_current_pos += i_samplessize;
5069                 p_sys->context.i_mdatbytesleft -= i_samplessize;
5070
5071                 /* dts */
5072                 mtime_t i_time = LeafGetMOOVTimeInChunk( p_chunk, i_nb_samples );
5073                 i_time += p_chunk->i_first_dts;
5074                 p_track->i_time = i_time;
5075                 p_block->i_dts = VLC_TS_0 + CLOCK_FREQ * i_time / p_track->i_timescale;
5076
5077                 /* pts */
5078                 int64_t i_delta = MP4_TrackGetPTSDelta( p_demux, p_track );
5079                 if( i_delta != -1 )
5080                     p_block->i_pts = p_block->i_dts + i_delta;
5081                 else if( p_track->fmt.i_cat != VIDEO_ES )
5082                     p_block->i_pts = p_block->i_dts;
5083                 else
5084                     p_block->i_pts = VLC_TS_INVALID;
5085
5086                 es_out_Send( p_demux->out, p_track->p_es, p_block );
5087
5088                 if ( p_demux->p_sys->i_pcr < VLC_TS_0 )
5089                 {
5090                     p_sys->i_time = p_track->i_time * p_sys->i_timescale / p_track->i_timescale;
5091                     p_demux->p_sys->i_pcr = MP4_GetMoviePTS( p_demux->p_sys );
5092                     es_out_Control( p_demux->out, ES_OUT_SET_PCR, VLC_TS_0 + p_demux->p_sys->i_pcr );
5093                 }
5094
5095             }
5096             else
5097             {
5098                 // sample size > left bytes
5099                 break;
5100             }
5101
5102             p_track->i_sample += i_samplescounttoread;
5103         }
5104
5105         /* flag end of mdat section if needed */
5106         if ( p_sys->context.i_mdatbytesleft == 0 )
5107             p_sys->context.i_current_box_type = 0;
5108
5109         // next chunk
5110         return VLC_SUCCESS;
5111     }
5112
5113 error:
5114     /* Skip if we didn't reach the end of mdat box */
5115     if ( p_sys->context.i_mdatbytesleft  > 0 )
5116     {
5117         msg_Err( p_demux, "mdat had still %"PRIu32" bytes unparsed as samples",
5118                  p_sys->context.i_mdatbytesleft );
5119         stream_ReadU32( p_demux->s, NULL, p_sys->context.i_mdatbytesleft );
5120     }
5121     p_sys->context.i_current_box_type = 0;
5122
5123     return VLC_SUCCESS;
5124 }
5125
5126 static mp4_track_t * LeafGetTrackByTrunPos( demux_t *p_demux, const uint64_t i_pos, const uint64_t i_moofpos )
5127 {
5128     demux_sys_t *p_sys = p_demux->p_sys;
5129
5130     for ( uint32_t i=0; i<p_sys->i_tracks; i++ )
5131     {
5132         mp4_track_t *p_track = &p_sys->track[i];
5133         if ( !p_track->context.p_trun || !p_track->context.p_tfhd )
5134             continue;
5135         const MP4_Box_data_trun_t *p_trun_data = p_track->context.BOXDATA(p_trun);
5136         uint64_t i_offset = 0;
5137
5138         if ( p_track->context.BOXDATA(p_tfhd)->i_flags & MP4_TFHD_BASE_DATA_OFFSET )
5139             i_offset = p_track->context.BOXDATA(p_tfhd)->i_base_data_offset;
5140         else
5141             i_offset = i_moofpos;
5142
5143         //if ( p_track->context.BOXDATA(p_tfhd)->i_flags & MP4_TFHD_DEFAULT_BASE_IS_MOOF )
5144           //  i_offset += i_moofpos;
5145
5146         if (p_trun_data->i_flags & MP4_TRUN_DATA_OFFSET)
5147             i_offset += p_trun_data->i_data_offset;
5148         else
5149             return p_track;
5150
5151         if ( i_offset == i_pos )
5152             return p_track;
5153     }
5154
5155     return NULL;
5156 }
5157
5158 static int LeafMapTrafTrunContextes( demux_t *p_demux, MP4_Box_t *p_moof )
5159 {
5160     demux_sys_t *p_sys = p_demux->p_sys;
5161
5162     /* reset */
5163     for ( uint32_t i=0; i<p_sys->i_tracks; i++ )
5164     {
5165         mp4_track_t *p_track = &p_sys->track[i];
5166         p_track->context.p_tfhd = NULL;
5167         p_track->context.p_traf = NULL;
5168         p_track->context.p_trun = NULL;
5169     }
5170
5171     if ( p_moof->i_type == ATOM_moov )
5172         return VLC_SUCCESS;
5173
5174     MP4_Box_t *p_traf = MP4_BoxGet( p_moof, "traf" );
5175     if( !p_traf )
5176     {
5177         msg_Warn( p_demux, "no traf box found!" );
5178         return VLC_EGENERIC;
5179     }
5180
5181     /* map contexts */
5182     while ( p_traf )
5183     {
5184         if ( p_traf->i_type == ATOM_traf )
5185         {
5186             MP4_Box_t *p_tfhd = MP4_BoxGet( p_traf, "tfhd" );
5187             for ( uint32_t i=0; p_tfhd && i<p_sys->i_tracks; i++ )
5188             {
5189                 mp4_track_t *p_track = &p_sys->track[i];
5190                 if ( BOXDATA(p_tfhd)->i_track_ID == p_track->i_track_ID )
5191                 {
5192                     MP4_Box_t *p_trun = MP4_BoxGet( p_traf, "trun" );
5193                     if ( p_trun )
5194                     {
5195                         p_track->context.p_tfhd = p_tfhd;
5196                         p_track->context.p_traf = p_traf;
5197                         p_track->context.p_trun = p_trun;
5198                     }
5199                     p_tfhd = NULL; /* break loop */
5200                 }
5201             }
5202         }
5203         p_traf = p_traf->p_next;
5204     }
5205
5206     return VLC_SUCCESS;
5207 }
5208
5209 static int LeafIndexGetMoofPosByTime( demux_t *p_demux, const mtime_t i_target_time,
5210                                       uint64_t *pi_pos, mtime_t *pi_mooftime )
5211 {
5212     MP4_Box_t *p_tfra = MP4_BoxGet( p_demux->p_sys->p_root, "mfra/tfra" );
5213     while ( p_tfra )
5214     {
5215         if ( p_tfra->i_type == ATOM_tfra )
5216         {
5217             int64_t i_pos = -1;
5218             const MP4_Box_data_tfra_t *p_data = BOXDATA(p_tfra);
5219             mp4_track_t *p_track = MP4_frg_GetTrackByID( p_demux, p_data->i_track_ID );
5220             if ( p_track && (p_track->fmt.i_cat == AUDIO_ES || p_track->fmt.i_cat == VIDEO_ES) )
5221             {
5222                 for ( uint32_t i = 0; i<p_data->i_number_of_entries; i += ( p_data->i_version == 1 ) ? 2 : 1 )
5223                 {
5224                     mtime_t i_time;
5225                     uint64_t i_offset;
5226                     if ( p_data->i_version == 1 )
5227                     {
5228                         i_time = *((uint64_t *)(p_data->p_time + i));
5229                         i_offset = *((uint64_t *)(p_data->p_moof_offset + i));
5230                     }
5231                     else
5232                     {
5233                         i_time = p_data->p_time[i];
5234                         i_offset = p_data->p_moof_offset[i];
5235                     }
5236
5237                     if ( CLOCK_FREQ * i_time / p_track->i_timescale >= i_target_time )
5238                     {
5239                         if ( i_pos == -1 ) /* Not in this traf */
5240                             break;
5241
5242                         *pi_pos = (uint64_t) i_pos;
5243                         *pi_mooftime = CLOCK_FREQ * i_time / p_track->i_timescale;
5244                         if ( p_track->fmt.i_cat == AUDIO_ES )
5245                             *pi_mooftime -= CLOCK_FREQ / p_track->fmt.audio.i_rate * p_data->p_sample_number[i];
5246                         else
5247                             *pi_mooftime -= CLOCK_FREQ / p_demux->p_sys->f_fps * p_data->p_sample_number[i];
5248                         return VLC_SUCCESS;
5249                     }
5250                     else
5251                         i_pos = i_offset;
5252                 }
5253             }
5254         }
5255         p_tfra = p_tfra->p_next;
5256     }
5257     return VLC_EGENERIC;
5258 }
5259
5260 static int LeafParseMDATwithMOOF( demux_t *p_demux, MP4_Box_t *p_moof )
5261 {
5262     demux_sys_t *p_sys = p_demux->p_sys;
5263     uint64_t i_pos;
5264     assert( p_moof->i_type == ATOM_moof );
5265     assert( p_sys->context.i_current_box_type == ATOM_mdat );
5266
5267     if ( p_sys->context.i_mdatbytesleft == 0 )
5268     {
5269         int i_ret = LeafMapTrafTrunContextes( p_demux, p_moof );
5270         if ( i_ret != VLC_SUCCESS )
5271             return i_ret;
5272
5273         /* Ready mdat section */
5274         uint8_t mdat[8];
5275         int i_read = stream_Read( p_demux->s, &mdat, 8 );
5276         p_sys->context.i_mdatbytesleft = GetDWBE( mdat );
5277         if ( i_read < 8 || p_sys->context.i_mdatbytesleft < 8 ||
5278              VLC_FOURCC( mdat[4], mdat[5], mdat[6], mdat[7] ) != ATOM_mdat )
5279         {
5280             if ( MP4_stream_Tell( p_demux->s, &i_pos ) )
5281                 msg_Err(p_demux, "No mdat atom at %"PRIu64, i_pos - i_read );
5282             return VLC_EGENERIC;
5283         }
5284         p_sys->context.i_mdatbytesleft -= 8;
5285     }
5286
5287     if ( !MP4_stream_Tell( p_demux->s, &i_pos ) )
5288         return VLC_EGENERIC;
5289     if ( p_sys->b_smooth )
5290         i_pos -= p_moof->i_pos;
5291     mp4_track_t *p_track = LeafGetTrackByTrunPos( p_demux, i_pos, p_moof->i_pos );
5292     if( p_track )
5293     {
5294         MP4_Box_data_tfhd_t *p_tfhd_data = p_track->context.BOXDATA(p_tfhd);
5295         uint32_t i_trun_sample_default_duration = 0;
5296         uint32_t i_trun_sample_default_size = 0;
5297
5298         if ( p_track->context.p_trun )
5299         {
5300             /* Get defaults for this/these RUN */
5301             if( p_tfhd_data->i_flags & MP4_TFHD_DFLT_SAMPLE_DURATION )
5302                 i_trun_sample_default_duration = p_tfhd_data->i_default_sample_duration;
5303
5304             if( p_tfhd_data->i_flags & MP4_TFHD_DFLT_SAMPLE_SIZE )
5305                 i_trun_sample_default_size = p_tfhd_data->i_default_sample_size;
5306
5307             if( !i_trun_sample_default_duration || !i_trun_sample_default_size )
5308             {
5309                 MP4_Box_t *p_trex = MP4_BoxGet( p_demux->p_sys->p_root, "moov/mvex/trex");
5310                 if ( p_trex )
5311                 {
5312                     while( p_trex && BOXDATA(p_trex)->i_track_ID != p_tfhd_data->i_track_ID )
5313                         p_trex = p_trex->p_next;
5314                     if ( p_trex && !i_trun_sample_default_duration )
5315                         i_trun_sample_default_duration = BOXDATA(p_trex)->i_default_sample_duration;
5316                     if ( p_trex && !i_trun_sample_default_size )
5317                         i_trun_sample_default_size = BOXDATA(p_trex)->i_default_sample_size;
5318                 }
5319             }
5320
5321         }
5322
5323         const MP4_Box_data_trun_t *p_trun_data = p_track->context.BOXDATA(p_trun);
5324
5325         /* NOW PARSE TRUN WITH MDAT */
5326         int i_ret = LeafParseTRUN( p_demux, p_track,
5327                                i_trun_sample_default_duration, i_trun_sample_default_size,
5328                                p_trun_data, & p_sys->context.i_mdatbytesleft );
5329         if ( i_ret != VLC_SUCCESS )
5330             goto end;
5331
5332         p_track->context.p_trun = p_track->context.p_trun->p_next;
5333         if ( p_sys->context.i_mdatbytesleft == 0 )
5334             p_sys->context.i_current_box_type = 0;
5335         return VLC_SUCCESS;
5336     }
5337
5338 end:
5339     /* Skip if we didn't reach the end of mdat box */
5340     if ( p_sys->context.i_mdatbytesleft > 0 )
5341     {
5342         msg_Warn( p_demux, "mdat had still %"PRIu32" bytes unparsed as samples", p_sys->context.i_mdatbytesleft - 8 );
5343         stream_ReadU32( p_demux->s, NULL, p_sys->context.i_mdatbytesleft );
5344     }
5345
5346     p_sys->context.i_current_box_type = 0;
5347
5348     return VLC_SUCCESS;
5349 }
5350
5351 static int DemuxAsLeaf( demux_t *p_demux )
5352 {
5353     demux_sys_t *p_sys = p_demux->p_sys;
5354     unsigned i_track_selected = 0;
5355
5356     /* check for newly selected/unselected track */
5357     for( unsigned i_track = 0; i_track < p_sys->i_tracks; i_track++ )
5358     {
5359         mp4_track_t *tk = &p_sys->track[i_track];
5360         bool b;
5361
5362         if( !tk->b_ok || tk->b_chapter )
5363             continue;
5364
5365         es_out_Control( p_demux->out, ES_OUT_GET_ES_STATE, tk->p_es, &b );
5366         msg_Dbg( p_demux, "track %u %s!", tk->i_track_ID, b ? "enabled" : "disabled" );
5367
5368         if( tk->b_selected && !b )
5369             MP4_TrackUnselect( p_demux, tk );
5370         else if( !tk->b_selected && b)
5371             MP4_frg_TrackSelect( p_demux, tk );
5372
5373         if( tk->b_selected )
5374             i_track_selected++;
5375     }
5376
5377     if( i_track_selected <= 0 )
5378     {
5379         msg_Warn( p_demux, "no track selected, exiting..." );
5380         return 0;
5381     }
5382
5383     if ( p_sys->context.i_current_box_type != ATOM_mdat )
5384     {
5385         /* Othewise mdat is skipped. FIXME: mdat reading ! */
5386         const uint8_t *p_peek;
5387         int i_read  = stream_Peek( p_demux->s, &p_peek, 8 );
5388         if ( i_read < 8 )
5389             return 0;
5390
5391         p_sys->context.i_current_box_type = VLC_FOURCC( p_peek[4], p_peek[5], p_peek[6], p_peek[7] );
5392
5393         if ( p_sys->context.i_current_box_type != ATOM_mdat )
5394         {
5395             if ( ! BoxExistsInRootTree( p_sys->p_root, p_sys->context.i_current_box_type, stream_Tell( p_demux->s ) ) )
5396             {// only if !b_probed ??
5397                 MP4_Box_t *p_vroot = LoadNextChunk( p_demux );
5398                 switch( p_sys->context.i_current_box_type )
5399                 {
5400                 case ATOM_moov:
5401                 case ATOM_moof:
5402                     /* create fragment */
5403                     AddFragment( p_demux, p_vroot->p_first );
5404                     //ft
5405                 default:
5406                     break;
5407                 }
5408
5409                 /* Append to root */
5410                 p_sys->p_root->p_last->p_next = p_vroot->p_first;
5411                 p_sys->p_root->p_last = p_vroot->p_first;
5412                 p_vroot->p_last = NULL;
5413                 p_vroot->p_next = NULL;
5414                 p_vroot->p_first = NULL;
5415                 MP4_BoxFree( p_demux->s, p_vroot );
5416             }
5417             else
5418             {
5419                 /* Skip */
5420                 msg_Err( p_demux, "skipping known chunk type %4.4s size %"PRIu32, (char*)& p_sys->context.i_current_box_type, GetDWBE( p_peek ) );
5421                 stream_Read( p_demux->s, NULL, GetDWBE( p_peek ) );
5422             }
5423         }
5424         else
5425         {
5426             /* skip mdat header */
5427             p_sys->context.p_fragment = GetFragmentByPos( p_demux,
5428                                        stream_Tell( p_demux->s ) + 8, true );
5429         }
5430
5431     }
5432
5433     if ( p_sys->context.i_current_box_type == ATOM_mdat )
5434     {
5435         assert(p_sys->context.p_fragment);
5436         if ( p_sys->context.p_fragment )
5437         switch( p_sys->context.p_fragment->p_moox->i_type )
5438         {
5439             case ATOM_moov://[ftyp/moov, mdat]+ -> [moof, mdat]+
5440                 LeafParseMDATwithMOOV( p_demux );
5441             break;
5442             case ATOM_moof:
5443                 LeafParseMDATwithMOOF( p_demux, p_sys->context.p_fragment->p_moox ); // BACKUP CHUNK!
5444             break;
5445         default:
5446              msg_Err( p_demux, "fragment type %4.4s", (char*) &p_sys->context.p_fragment->p_moox->i_type );
5447              break;
5448         }
5449     }
5450
5451     /* Get current time */
5452     mtime_t i_lowest_dts = VLC_TS_INVALID;
5453     mtime_t i_lowest_time = INT64_MAX;
5454     for( unsigned int i_track = 0; i_track < p_sys->i_tracks; i_track++ )
5455     {
5456         const mp4_track_t *p_track = &p_sys->track[i_track];
5457         if( !p_track->b_selected || ( p_track->fmt.i_cat != VIDEO_ES && p_track->fmt.i_cat != AUDIO_ES ) )
5458             continue;
5459
5460         i_lowest_time = __MIN( i_lowest_time, p_track->i_time * p_sys->i_timescale / p_track->i_timescale );
5461
5462         if ( i_lowest_dts == VLC_TS_INVALID )
5463             i_lowest_dts = CLOCK_FREQ * p_track->i_time / p_track->i_timescale;
5464         else
5465             i_lowest_dts = __MIN( i_lowest_dts, CLOCK_FREQ * p_track->i_time / p_track->i_timescale );
5466     }
5467
5468     p_sys->i_time = i_lowest_time;
5469     p_sys->i_pcr = i_lowest_dts;
5470     es_out_Control( p_demux->out, ES_OUT_SET_PCR, VLC_TS_0 + p_sys->i_pcr );
5471
5472     return 1;
5473 }
5474
5475 #undef BOXDATA