demux: mp4: switch to seekmode if non interleaved (fix #11707)
authorFrancois Cartegnie <fcvlcdev@free.fr>
Fri, 18 Jul 2014 06:43:06 +0000 (15:43 +0900)
committerFrancois Cartegnie <fcvlcdev@free.fr>
Fri, 18 Jul 2014 08:38:09 +0000 (17:38 +0900)
modules/demux/mp4/mp4.c

index e720e1b..929992e 100644 (file)
@@ -83,6 +83,7 @@ struct demux_sys_t
     bool         b_fragmented;   /* fMP4 */
     bool         b_seekable;
     bool         b_fastseekable;
+    bool         b_seekmode;
     bool         b_smooth;       /* Is it Smooth Streaming? */
 
     bool            b_index_probed;
@@ -440,6 +441,7 @@ static int Open( vlc_object_t * p_this )
         return VLC_EGENERIC;
     }
     stream_Control( p_demux->s, STREAM_CAN_FASTSEEK, &p_sys->b_fastseekable );
+    p_sys->b_seekmode = p_sys->b_fastseekable;
 
     /*Set exported functions */
     p_demux->pf_demux = Demux;
@@ -836,17 +838,32 @@ static int Demux( demux_t *p_demux )
     /* Find next track matching contiguous data */
     mp4_track_t *tk = NULL;
     uint64_t i_candidate_pos = UINT64_MAX;
+    mtime_t i_candidate_dts = INT64_MAX;
     for( i_track = 0; i_track < p_sys->i_tracks; i_track++ )
     {
         mp4_track_t *tk_tmp = &p_sys->track[i_track];
         if( !tk_tmp->b_ok || tk_tmp->b_chapter || !tk_tmp->b_selected || tk_tmp->i_sample >= tk_tmp->i_sample_count )
             continue;
 
-        uint64_t i_pos = MP4_TrackGetPos( tk_tmp );
-        if ( i_pos <= i_candidate_pos )
+        if ( p_sys->b_seekmode )
         {
-            i_candidate_pos = i_pos;
-            tk = tk_tmp;
+            mtime_t i_dts = MP4_TrackGetDTS( p_demux, tk_tmp );
+            if ( i_dts <= i_candidate_dts )
+            {
+                tk = tk_tmp;
+                i_candidate_dts = i_dts;
+                i_candidate_pos = MP4_TrackGetPos( tk_tmp );
+            }
+        }
+        else
+        {
+            /* Try to avoid seeking on non fastseekable. Will fail with non interleaved content */
+            uint64_t i_pos = MP4_TrackGetPos( tk_tmp );
+            if ( i_pos <= i_candidate_pos )
+            {
+                i_candidate_pos = i_pos;
+                tk = tk_tmp;
+            }
         }
     }
 
@@ -855,6 +872,16 @@ static int Demux( demux_t *p_demux )
         msg_Dbg( p_demux, "Could not select track by data position" );
         goto end;
     }
+    else if ( p_sys->b_seekmode )
+    {
+        if( stream_Seek( p_demux->s, i_candidate_pos ) )
+        {
+            msg_Warn( p_demux, "track[0x%x] will be disabled (eof?)",
+                      tk->i_track_ID );
+            MP4_TrackUnselect( p_demux, tk );
+            goto end;
+        }
+    }
 
 #if 0
     msg_Dbg( p_demux, "tk(%i)=%"PRId64" mv=%"PRId64" pos=%"PRIu64, i_track,
@@ -933,7 +960,15 @@ end:
             if ( !tk->b_ok || !tk->b_selected  ||
                  (tk->fmt.i_cat != AUDIO_ES && tk->fmt.i_cat != VIDEO_ES) )
                 continue;
-            p_sys->i_pcr = __MIN( MP4_TrackGetDTS( p_demux, tk ), p_sys->i_pcr );
+
+            mtime_t i_dts = MP4_TrackGetDTS( p_demux, tk );
+            if ( !p_sys->b_seekmode && i_dts > p_sys->i_pcr + 2*CLOCK_FREQ )
+            {
+                msg_Dbg( p_demux, "that media doesn't look interleaved, will need to seek");
+                p_sys->b_seekmode = true;
+            }
+
+            p_sys->i_pcr = __MIN( i_dts, p_sys->i_pcr );
             p_sys->i_time = p_sys->i_pcr * p_sys->i_timescale / CLOCK_FREQ;
         }
     }