[vlc-commits] demux: mp4: fix and improve interleaving detection

Francois Cartegnie git at videolan.org
Mon Oct 31 19:22:49 CET 2016


vlc | branch: master | Francois Cartegnie <fcvlcdev at free.fr> | Fri Oct 28 23:10:50 2016 +0200| [daca57aeccb49009cdbabcc04d60d55242880a33] | committer: Francois Cartegnie

demux: mp4: fix and improve interleaving detection

On compressed content, all chunks are separate

> http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=daca57aeccb49009cdbabcc04d60d55242880a33
---

 modules/demux/mp4/mp4.c | 84 ++++++++++++++++++++++++++++++++++++-------------
 1 file changed, 62 insertions(+), 22 deletions(-)

diff --git a/modules/demux/mp4/mp4.c b/modules/demux/mp4/mp4.c
index 15fbb59..4b98566 100644
--- a/modules/demux/mp4/mp4.c
+++ b/modules/demux/mp4/mp4.c
@@ -124,7 +124,6 @@ static uint64_t MP4_TrackGetPos    ( mp4_track_t * );
 static uint32_t MP4_TrackGetReadSize( mp4_track_t *, uint32_t * );
 static int      MP4_TrackNextSample( demux_t *, mp4_track_t *, uint32_t );
 static void     MP4_TrackSetELST( demux_t *, mp4_track_t *, int64_t );
-static bool     MP4_TrackIsInterleaved( const mp4_track_t * );
 
 static void     MP4_UpdateSeekpoint( demux_t * );
 
@@ -401,6 +400,64 @@ static block_t * MP4_EIA608_Convert( block_t * p_block )
     return p_newblock;
 }
 
+/* Analyzes chunks to find max interleave length
+ * sets flat flag if no interleaving is in use */
+static void MP4_GetInterleaving( demux_t *p_demux, uint64_t *pi_max_contiguous, bool *pb_flat )
+{
+    demux_sys_t *p_sys = p_demux->p_sys;
+    *pi_max_contiguous = 0;
+    *pb_flat = true;
+
+    /* Find first recorded chunk */
+    mp4_track_t *tk = NULL;
+    uint64_t i_duration = 0;
+    for( unsigned i=0; i < p_sys->i_tracks; i++ )
+    {
+        mp4_track_t *cur = &p_sys->track[i];
+        if( !cur->i_chunk_count )
+            continue;
+
+        if( tk == NULL || cur->chunk[0].i_offset < tk->chunk[0].i_offset )
+            tk = cur;
+    }
+
+    for( ; tk != NULL; )
+    {
+        i_duration += tk->chunk[tk->i_chunk].i_duration;
+        tk->i_chunk++;
+
+        /* Find next chunk in data order */
+        mp4_track_t *nexttk = NULL;
+        for( unsigned i=0; i < p_sys->i_tracks; i++ )
+        {
+            mp4_track_t *cur = &p_sys->track[i];
+            if( cur->i_chunk == cur->i_chunk_count )
+                continue;
+
+            if( nexttk == NULL ||
+                cur->chunk[cur->i_chunk].i_offset < nexttk->chunk[nexttk->i_chunk].i_offset )
+                nexttk = cur;
+        }
+
+        if( tk != nexttk )
+        {
+            i_duration = i_duration * CLOCK_FREQ / tk->i_timescale;
+            if( i_duration > *pi_max_contiguous )
+                *pi_max_contiguous = i_duration;
+            i_duration = 0;
+
+            if( tk->i_chunk != tk->i_chunk_count )
+                *pb_flat = false;
+        }
+
+        tk = nexttk;
+    }
+
+    /* reset */
+    for( unsigned i=0; i < p_sys->i_tracks; i++ )
+        p_sys->track[i].i_chunk = 0;
+}
+
 static block_t * MP4_Block_Read( demux_t *p_demux, const mp4_track_t *p_track, int i_size )
 {
     block_t *p_block = vlc_stream_Block( p_demux->s, i_size );
@@ -844,15 +901,13 @@ static int Open( vlc_object_t * p_this )
 
     if( !p_sys->b_fragmented && p_sys->i_tracks > 1 && p_sys->b_seekable && !p_sys->b_seekmode )
     {
-        for( unsigned i = 0; i < p_sys->i_tracks; i++ )
+        uint64_t i_max_continuity;
+        bool b_flat;
+        MP4_GetInterleaving( p_demux, &i_max_continuity, &b_flat );
+        if( b_flat )
         {
-            mp4_track_t *tk = &p_sys->track[i];
-            if( !MP4_TrackIsInterleaved( tk ) )
-            {
                 msg_Warn( p_demux, "that media doesn't look interleaved, will need to seek");
                 p_sys->b_seekmode = true;
-                break;
-            }
         }
     }
 
@@ -1942,21 +1997,6 @@ static void LoadChapter( demux_t  *p_demux )
     }
 }
 
-static bool MP4_TrackIsInterleaved( const mp4_track_t *p_track )
-{
-    const MP4_Box_t *p_stsc = MP4_BoxGet( p_track->p_stbl, "stsc" );
-    const MP4_Box_t *p_stsz = MP4_BoxGet( p_track->p_stbl, "stsz" );
-    if( p_stsc && BOXDATA(p_stsc) && p_stsz && BOXDATA(p_stsz) )
-    {
-        if( BOXDATA(p_stsc)->i_entry_count == 1 &&
-            BOXDATA(p_stsz)->i_sample_count > 1 &&
-            BOXDATA(p_stsc)->i_samples_per_chunk[0] == BOXDATA(p_stsz)->i_sample_count )
-            return false;
-    }
-
-    return true;
-}
-
 /* now create basic chunk data, the rest will be filled by MP4_CreateSamplesIndex */
 static int TrackCreateChunksIndex( demux_t *p_demux,
                                    mp4_track_t *p_demux_track )



More information about the vlc-commits mailing list