]> git.sesse.net Git - vlc/blobdiff - modules/demux/mkv/matroska_segment.cpp
Matroska: cleanup so that relevant methods are in their correct files
[vlc] / modules / demux / mkv / matroska_segment.cpp
index 53459f852343eb209b1be229c18ff9987b4208ad..910d980bd257dcf7b30243f0e0c98d9e0c19791c 100644 (file)
@@ -604,6 +604,152 @@ bool matroska_segment_c::LoadSeekHeadItem( const EbmlCallbacks & ClassInfos, int
     return true;
 }
 
+void matroska_segment_c::Seek( mtime_t i_date, mtime_t i_time_offset, int64_t i_global_position )
+{
+    KaxBlock    *block;
+    KaxSimpleBlock *simpleblock;
+    int         i_track_skipping;
+    int64_t     i_block_duration;
+    int64_t     i_block_ref1;
+    int64_t     i_block_ref2;
+    size_t      i_track;
+    int64_t     i_seek_position = i_start_pos;
+    int64_t     i_seek_time = i_start_time;
+
+    if( i_global_position >= 0 )
+    {
+        /* Special case for seeking in files with no cues */
+        EbmlElement *el = NULL;
+        es.I_O().setFilePointer( i_start_pos, seek_beginning );
+        delete ep;
+        ep = new EbmlParser( &es, segment, &sys.demuxer );
+        cluster = NULL;
+
+        while( ( el = ep->Get() ) != NULL )
+        {
+            if( MKV_IS_ID( el, KaxCluster ) )
+            {
+                cluster = (KaxCluster *)el;
+                i_cluster_pos = cluster->GetElementPosition();
+                if( i_index == 0 ||
+                        ( i_index > 0 && p_indexes[i_index - 1].i_position < (int64_t)cluster->GetElementPosition() ) )
+                {
+                    IndexAppendCluster( cluster );
+                }
+                if( es.I_O().getFilePointer() >= i_global_position )
+                {
+                    ParseCluster();
+                    msg_Dbg( &sys.demuxer, "we found a cluster that is in the neighbourhood" );
+                    return;
+                }
+            }
+        }
+        msg_Err( &sys.demuxer, "This file has no cues, and we were unable to seek to the requested position by parsing." );
+        return;
+    }
+
+    if ( i_index > 0 )
+    {
+        int i_idx = 0;
+
+        for( ; i_idx < i_index; i_idx++ )
+        {
+            if( p_indexes[i_idx].i_time + i_time_offset > i_date )
+            {
+                break;
+            }
+        }
+
+        if( i_idx > 0 )
+        {
+            i_idx--;
+        }
+
+        i_seek_position = p_indexes[i_idx].i_position;
+        i_seek_time = p_indexes[i_idx].i_time;
+    }
+
+    msg_Dbg( &sys.demuxer, "seek got %"PRId64" (%d%%)",
+                i_seek_time, (int)( 100 * i_seek_position / stream_Size( sys.demuxer.s ) ) );
+
+    es.I_O().setFilePointer( i_seek_position, seek_beginning );
+
+    delete ep;
+    ep = new EbmlParser( &es, segment, &sys.demuxer );
+    cluster = NULL;
+
+    sys.i_start_pts = i_date;
+
+    /* now parse until key frame */
+    i_track_skipping = 0;
+    for( i_track = 0; i_track < tracks.size(); i_track++ )
+    {
+        if( tracks[i_track]->fmt.i_cat == VIDEO_ES )
+        {
+            tracks[i_track]->b_search_keyframe = true;
+            i_track_skipping++;
+        }
+    }
+    es_out_Control( sys.demuxer.out, ES_OUT_SET_NEXT_DISPLAY_TIME, i_date );
+
+    while( i_track_skipping > 0 )
+    {
+        if( BlockGet( block, simpleblock, &i_block_ref1, &i_block_ref2, &i_block_duration ) )
+        {
+            msg_Warn( &sys.demuxer, "cannot get block EOF?" );
+
+            return;
+        }
+
+        for( i_track = 0; i_track < tracks.size(); i_track++ )
+        {
+            if( (simpleblock && tracks[i_track]->i_number == simpleblock->TrackNum()) ||
+                (block && tracks[i_track]->i_number == block->TrackNum()) )
+            {
+                break;
+            }
+        }
+
+        if( simpleblock )
+            sys.i_pts = (sys.i_chapter_time + simpleblock->GlobalTimecode()) / (mtime_t) 1000;
+        else
+            sys.i_pts = (sys.i_chapter_time + block->GlobalTimecode()) / (mtime_t) 1000;
+
+        if( i_track < tracks.size() )
+        {
+            if( sys.i_pts > sys.i_start_pts )
+            {
+                cluster = static_cast<KaxCluster*>(ep->UnGet( i_block_pos, i_cluster_pos ));
+                i_track_skipping = 0;
+            }
+            else if( tracks[i_track]->fmt.i_cat == VIDEO_ES )
+            {
+                if( i_block_ref1 == 0 && tracks[i_track]->b_search_keyframe )
+                {
+                    tracks[i_track]->b_search_keyframe = false;
+                    i_track_skipping--;
+                }
+                if( !tracks[i_track]->b_search_keyframe )
+                {
+                    BlockDecode( &sys.demuxer, block, simpleblock, sys.i_pts, 0, i_block_ref1 >= 0 || i_block_ref2 > 0 );
+                }
+            }
+        }
+
+        delete block;
+    }
+
+    /* FIXME current ES_OUT_SET_NEXT_DISPLAY_TIME does not work that well if
+     * the delay is too high. */
+    if( sys.i_pts + 500*1000 < sys.i_start_pts )
+    {
+        sys.i_start_pts = sys.i_pts;
+
+        es_out_Control( sys.demuxer.out, ES_OUT_SET_NEXT_DISPLAY_TIME, sys.i_start_pts );
+    }
+}
+
+
 int matroska_segment_c::BlockFindTrackIndex( size_t *pi_track,
                                              const KaxBlock *p_block, const KaxSimpleBlock *p_simpleblock )
 {