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