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