Commit e133d979 authored by François Cartegnie's avatar François Cartegnie 🤞

demux: mp4: rework durations handling

parent b4bb0efb
......@@ -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;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment