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