[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