[vlc-commits] demux: mp4: rework durations handling
Francois Cartegnie
git at videolan.org
Mon Feb 6 20:08:06 CET 2017
vlc | branch: master | Francois Cartegnie <fcvlcdev at free.fr> | Mon Feb 6 19:45:34 2017 +0100| [e133d979c29d1e60b7e712ce5271392a0c8a7adb] | committer: Francois Cartegnie
demux: mp4: rework durations handling
> http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=e133d979c29d1e60b7e712ce5271392a0c8a7adb
---
modules/demux/mp4/mp4.c | 126 +++++++++++++++++++++++++++++-------------------
1 file changed, 77 insertions(+), 49 deletions(-)
diff --git a/modules/demux/mp4/mp4.c b/modules/demux/mp4/mp4.c
index 02e5bec..9f17352 100644
--- a/modules/demux/mp4/mp4.c
+++ b/modules/demux/mp4/mp4.c
@@ -76,7 +76,9 @@ struct demux_sys_t
mtime_t i_pcr;
- uint64_t i_overall_duration; /* Full duration, including all fragments */
+ uint64_t i_moov_duration;
+ uint64_t i_duration; /* Declared fragmented duration */
+ uint64_t i_cumulated_duration; /* Same as above, but not from probing */
uint64_t i_time; /* time position of the presentation
* in movie timescale */
uint32_t i_timescale; /* movie time scale */
@@ -148,7 +150,7 @@ static void MP4_GetDefaultSizeAndDuration( demux_t *p_demux,
uint32_t *pi_default_duration );
static bool AddFragment( demux_t *p_demux, MP4_Box_t *p_moox );
-static int ProbeFragments( demux_t *p_demux, bool b_force );
+static int ProbeFragments( demux_t *p_demux, bool b_force, bool *pb_fragmented );
static int ProbeIndex( demux_t *p_demux );
static int LeafIndexGetMoofPosByTime( demux_t *p_demux, const mtime_t i_target_time,
@@ -629,9 +631,11 @@ static int Open( vlc_object_t * p_this )
const uint8_t *p_peek;
MP4_Box_t *p_ftyp;
+ MP4_Box_t *p_moov;
MP4_Box_t *p_rmra;
- MP4_Box_t *p_mvhd;
MP4_Box_t *p_trak;
+ const MP4_Box_t *p_mvhd = NULL;
+ const MP4_Box_t *p_mvex = NULL;
unsigned int i;
bool b_enabled_es;
@@ -739,19 +743,36 @@ static int Open( vlc_object_t * p_this )
msg_Dbg( p_demux, "file type box missing (assuming ISO Media)" );
}
- if( MP4_BoxCount( p_sys->p_root, "/moov/mvex" ) > 0 )
+ p_moov = MP4_BoxGet( p_sys->p_root, "/moov" );
+ if( likely(p_moov) )
{
- const MP4_Box_t *p_moov = MP4_BoxGet( p_sys->p_root, "/moov" );
- if ( p_sys->b_seekable )
+ p_mvhd = MP4_BoxGet( p_moov, "mvhd" );
+ if( p_mvhd && BOXDATA(p_mvhd) )
+ p_sys->i_moov_duration = p_sys->i_duration = BOXDATA(p_mvhd)->i_duration;
+ p_mvex = MP4_BoxGet( p_moov, "mvex" );
+ }
+
+ if( p_mvex != NULL )
+ {
+ const MP4_Box_t *p_mehd = MP4_BoxGet( p_mvex, "mehd");
+ if ( p_mehd && BOXDATA(p_mehd) )
{
- /* Probe remaining to check if there's really fragments
- or if that file is just ready to append fragments */
- ProbeFragments( p_demux, false );
- const MP4_Box_t *p_moof = MP4_BoxGet( p_sys->p_root, "/moof" );
- p_sys->b_fragmented = !!p_moof;
+ if( BOXDATA(p_mehd)->i_fragment_duration > p_sys->i_duration )
+ {
+ p_sys->b_fragmented = true;
+ p_sys->i_duration = BOXDATA(p_mehd)->i_fragment_duration;
+ }
+ }
- if ( p_sys->b_fragmented && !p_sys->i_overall_duration )
- ProbeFragments( p_demux, true );
+ if ( p_sys->b_seekable )
+ {
+ if( !p_sys->b_fragmented /* as unknown */ )
+ {
+ /* Probe remaining to check if there's really fragments
+ or if that file is just ready to append fragments */
+ ProbeFragments( p_demux, (p_sys->i_duration == 0), &p_sys->b_fragmented );
+ p_sys->b_fragmented = !! MP4_BoxGet( p_sys->p_root, "/moof" );
+ }
if( vlc_stream_Seek( p_demux->s, p_moov->i_pos ) != VLC_SUCCESS )
goto error;
@@ -977,22 +998,6 @@ static int Open( vlc_object_t * p_this )
}
}
- if ( p_sys->i_overall_duration == 0 )
- {
- /* Try in mehd if fragmented */
- MP4_Box_t *p_mehd = MP4_BoxGet( p_demux->p_sys->p_root, "moov/mvex/mehd");
- if ( p_mehd && p_mehd->data.p_mehd )
- p_sys->i_overall_duration = p_mehd->data.p_mehd->i_fragment_duration;
- else
- {
- for( i = 0; i < p_sys->i_tracks; i++ )
- {
- mtime_t i_duration = GetTrackTotalDuration( &p_sys->fragments, p_sys->track[i].i_track_ID );
- p_sys->i_overall_duration = __MAX( p_sys->i_overall_duration, (uint64_t)i_duration );
- }
- }
- }
-
#ifdef MP4_VERBOSE
DumpFragments( VLC_OBJECT(p_demux), &p_sys->fragments, p_sys->i_timescale );
#endif
@@ -1478,7 +1483,8 @@ static int LeafSeekToTime( demux_t *p_demux, mtime_t i_nztime )
demux_sys_t *p_sys = p_demux->p_sys;
mp4_fragment_t *p_fragment = NULL;
uint64_t i64 = 0;
- if ( !p_sys->i_timescale || !p_sys->i_overall_duration || !p_sys->b_seekable )
+ const uint64_t i_duration = __MAX(p_sys->i_duration, p_sys->i_cumulated_duration);
+ if ( !p_sys->i_timescale || !i_duration || !p_sys->b_seekable )
return VLC_EGENERIC;
if ( !p_sys->b_fragments_probed && !p_sys->b_index_probed && p_sys->b_seekable )
@@ -1507,7 +1513,17 @@ static int LeafSeekToTime( demux_t *p_demux, mtime_t i_nztime )
{
mtime_t i_mooftime;
msg_Dbg( p_demux, "seek can't find matching fragment for %"PRId64", trying index", i_nztime );
- if ( LeafIndexGetMoofPosByTime( p_demux, i_nztime, &i64, &i_mooftime ) == VLC_SUCCESS )
+ if( (uint64_t)MP4_rescale( i_nztime, CLOCK_FREQ, p_sys->i_timescale ) < p_sys->i_moov_duration )
+ {
+ i64 = p_sys->fragments.moov.p_moox->i_pos;
+ i_mooftime = i_nztime;
+ }
+ else if( LeafIndexGetMoofPosByTime( p_demux, i_nztime, &i64, &i_mooftime ) != VLC_SUCCESS )
+ {
+ i64 = UINT64_MAX;
+ }
+
+ if ( i64 != UINT64_MAX )
{
msg_Dbg( p_demux, "seek trying to go to unknown but indexed fragment at %"PRId64, i64 );
if( vlc_stream_Seek( p_demux->s, i64 ) )
@@ -1551,11 +1567,12 @@ static int LeafSeekToPos( demux_t *p_demux, double f )
if ( !p_sys->b_seekable )
return VLC_EGENERIC;
- if ( p_sys->i_timescale && p_sys->i_overall_duration )
+ const uint64_t i_duration = __MAX(p_sys->i_duration, p_sys->i_cumulated_duration);
+ if ( p_sys->i_timescale && i_duration )
{
return LeafSeekToTime( p_demux,
(mtime_t)( f *
- MP4_rescale( p_sys->i_overall_duration, p_sys->i_timescale, CLOCK_FREQ ) ) );
+ MP4_rescale( i_duration, p_sys->i_timescale, CLOCK_FREQ ) ) );
}
if ( !p_sys->b_fragments_probed && !p_sys->b_index_probed && p_sys->b_seekable )
@@ -1595,7 +1612,8 @@ static int MP4_frg_Seek( demux_t *p_demux, double f )
else
{
/* update global time */
- p_sys->i_time = (uint64_t)(f * (double)p_sys->i_overall_duration);
+ const uint64_t i_duration = __MAX(p_sys->i_duration, p_sys->i_cumulated_duration);
+ p_sys->i_time = (uint64_t)(f * (double)i_duration);
p_sys->i_pcr = MP4_GetMoviePTS( p_sys );
for( unsigned i_track = 0; i_track < p_sys->i_tracks; i_track++ )
@@ -1643,6 +1661,7 @@ static int Control( demux_t *p_demux, int i_query, va_list args )
"/udta",
NULL };
const uint32_t rgi_pict_atoms[2] = { ATOM_PICT, ATOM_pict };
+ const uint64_t i_duration = __MAX(p_sys->i_duration, p_sys->i_cumulated_duration);
switch( i_query )
{
@@ -1652,9 +1671,9 @@ static int Control( demux_t *p_demux, int i_query, va_list args )
case DEMUX_GET_POSITION:
pf = (double*)va_arg( args, double * );
- if( p_sys->i_overall_duration > 0 )
+ if( i_duration > 0 )
{
- *pf = (double)p_sys->i_time / (double)p_sys->i_overall_duration;
+ *pf = (double)p_sys->i_time / (double)i_duration;
}
else
{
@@ -1670,7 +1689,7 @@ static int Control( demux_t *p_demux, int i_query, va_list args )
return MP4_frg_Seek( p_demux, f );
else if( p_sys->i_timescale > 0 )
{
- i64 = (int64_t)( f * MP4_rescale( p_sys->i_overall_duration,
+ i64 = (int64_t)( f * MP4_rescale( p_sys->i_duration,
p_sys->i_timescale, CLOCK_FREQ ) );
return Seek( p_demux, i64 );
}
@@ -1697,7 +1716,7 @@ static int Control( demux_t *p_demux, int i_query, va_list args )
pi64 = (int64_t*)va_arg( args, int64_t * );
if( p_sys->i_timescale > 0 )
{
- *pi64 = MP4_rescale( p_sys->i_overall_duration,
+ *pi64 = MP4_rescale( i_duration,
p_sys->i_timescale, CLOCK_FREQ );
}
else *pi64 = 0;
@@ -2101,8 +2120,9 @@ static void LoadChapter( demux_t *p_demux )
/* Add duration if titles are enabled */
if( p_sys->p_title )
{
+ const uint64_t i_duration = __MAX(p_sys->i_duration, p_sys->i_cumulated_duration);
p_sys->p_title->i_length =
- MP4_rescale( p_sys->i_overall_duration,
+ MP4_rescale( i_duration,
p_sys->i_timescale, CLOCK_FREQ );
}
}
@@ -4139,7 +4159,8 @@ int DemuxFrg( demux_t *p_demux )
p_sys->i_time += __MAX( p_sys->i_timescale / 10 , 1 );
if( p_sys->i_timescale > 0 )
{
- int64_t i_length = MP4_rescale( p_sys->i_overall_duration,
+ const uint64_t i_duration = __MAX(p_sys->i_duration, p_sys->i_cumulated_duration);
+ int64_t i_length = MP4_rescale( i_duration,
p_sys->i_timescale, CLOCK_FREQ );
if( MP4_GetMoviePTS( p_sys ) >= i_length )
return VLC_DEMUXER_EOF;
@@ -4253,12 +4274,12 @@ static bool AddFragment( demux_t *p_demux, MP4_Box_t *p_moox )
if( (p_mvhd = MP4_BoxGet( p_moox, "mvhd" )) )
{
p_sys->i_timescale = BOXDATA(p_mvhd)->i_timescale;
- p_sys->i_overall_duration = BOXDATA(p_mvhd)->i_duration;
+ p_sys->i_cumulated_duration = BOXDATA(p_mvhd)->i_duration;
}
else
{
p_sys->i_timescale = CLOCK_FREQ;
- p_sys->i_overall_duration = CLOCK_FREQ;
+ p_sys->i_cumulated_duration = CLOCK_FREQ;
msg_Warn( p_demux, "No valid mvhd found" );
}
@@ -4471,13 +4492,12 @@ static bool AddFragment( demux_t *p_demux, MP4_Box_t *p_moox )
if ( !p_mehd )
{
if ( p_sys->b_fragments_probed )
- p_sys->i_overall_duration = SumFragmentsDurations( p_demux );
+ p_sys->i_cumulated_duration = SumFragmentsDurations( p_demux );
}
- else
- p_sys->i_overall_duration = BOXDATA(p_mehd)->i_fragment_duration;
- msg_Dbg( p_demux, "total fragments duration %"PRId64, MP4_rescale( p_sys->i_overall_duration,
- p_sys->i_timescale, CLOCK_FREQ ) );
+ const uint64_t i_duration = __MAX(p_sys->i_duration, p_sys->i_cumulated_duration);
+ msg_Dbg( p_demux, "total fragments duration %"PRId64,
+ MP4_rescale( i_duration, p_sys->i_timescale, CLOCK_FREQ ) );
return true;
}
@@ -4520,7 +4540,7 @@ static int ProbeIndex( demux_t *p_demux )
return vlc_stream_Seek( p_demux->s, i_backup_pos );
}
-static int ProbeFragments( demux_t *p_demux, bool b_force )
+static int ProbeFragments( demux_t *p_demux, bool b_force, bool *pb_fragmented )
{
demux_sys_t *p_sys = p_demux->p_sys;
uint64_t i_current_pos = vlc_stream_Tell( p_demux->s );
@@ -4533,6 +4553,7 @@ static int ProbeFragments( demux_t *p_demux, bool b_force )
{
MP4_ReadBoxContainerChildren( p_demux->s, p_sys->p_root, NULL ); /* Get the rest of the file */
p_sys->b_fragments_probed = true;
+ *pb_fragmented = MP4_BoxGet( p_sys->p_root, "/moof" );
}
else
{
@@ -4540,6 +4561,12 @@ static int ProbeFragments( demux_t *p_demux, bool b_force )
* and we'll find others while reading. */
const uint32_t excllist[] = { ATOM_moof, 0 };
MP4_ReadBoxContainerRestricted( p_demux->s, p_sys->p_root, NULL, excllist );
+ /* Peek since we stopped before restriction */
+ const uint8_t *p_peek;
+ if ( vlc_stream_Peek( p_demux->s, &p_peek, 8 ) == 8 )
+ *pb_fragmented = (VLC_FOURCC( p_peek[4], p_peek[5], p_peek[6], p_peek[7] ) == ATOM_moof);
+ else
+ *pb_fragmented = false;
}
if ( !MP4_Fragment_Moov( &p_sys->fragments )->p_moox )
@@ -5012,6 +5039,7 @@ static int LeafIndexGetMoofPosByTime( demux_t *p_demux, const mtime_t i_target_t
mp4_track_t *p_track = MP4_frg_GetTrackByID( p_demux, p_data->i_track_ID );
if ( p_track && (p_track->fmt.i_cat == AUDIO_ES || p_track->fmt.i_cat == VIDEO_ES) )
{
+ uint64_t i_track_target_time = MP4_rescale( i_target_time, CLOCK_FREQ, p_track->i_timescale );
for ( uint32_t i = 0; i<p_data->i_number_of_entries; i += ( p_data->i_version == 1 ) ? 2 : 1 )
{
mtime_t i_time;
@@ -5027,7 +5055,7 @@ static int LeafIndexGetMoofPosByTime( demux_t *p_demux, const mtime_t i_target_t
i_offset = p_data->p_moof_offset[i];
}
- if ( MP4_rescale( i_time, p_track->i_timescale, CLOCK_FREQ ) >= i_target_time )
+ if ( (uint64_t)i_time >= i_track_target_time )
{
if ( i_pos == -1 ) /* Not in this traf */
break;
More information about the vlc-commits
mailing list