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