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