]> git.sesse.net Git - vlc/blobdiff - modules/demux/mkv.cpp
Do not leave the index building progress bar opened when exit is requested.
[vlc] / modules / demux / mkv.cpp
index ceaa77ae0eaf29981c9bacef4511033003528c3c..bf127da59931083b99d71c0e909e480321d21115 100644 (file)
@@ -520,8 +520,8 @@ class vlc_stream_io_callback: public IOCallback
 {
   private:
     stream_t       *s;
-    bool     mb_eof;
-    bool     b_owner;
+    bool           mb_eof;
+    bool           b_owner;
 
   public:
     vlc_stream_io_callback( stream_t *, bool );
@@ -569,8 +569,8 @@ class EbmlParser
     EbmlElement *m_got;
 
     int         mi_user_level;
-    bool  mb_keep;
-    bool  mb_dummy;
+    bool        mb_keep;
+    bool        mb_dummy;
 };
 
 
@@ -590,8 +590,8 @@ typedef struct
 {
 //    ~mkv_track_t();
 
-    bool   b_default;
-    bool   b_enabled;
+    bool         b_default;
+    bool         b_enabled;
     unsigned int i_number;
 
     int          i_extra_data;
@@ -611,14 +611,14 @@ typedef struct
     /* audio */
     unsigned int i_original_rate;
 
-    bool      b_inited;
+    bool            b_inited;
     /* data to be send first */
     int             i_data_init;
     uint8_t         *p_data_init;
 
     /* hack : it's for seek */
-    bool      b_search_keyframe;
-    bool      b_silent;
+    bool            b_search_keyframe;
+    bool            b_silent;
 
     /* informative */
     const char   *psz_codec_name;
@@ -640,7 +640,7 @@ typedef struct
     int64_t i_position;
     int64_t i_time;
 
-    bool b_key;
+    bool       b_key;
 } mkv_index_t;
 
 class demux_sys_t;
@@ -1027,9 +1027,13 @@ public:
         ,i_duration(-1)
         ,i_start_time(0)
         ,i_cues_position(-1)
+        ,i_info_position(-1)
         ,i_chapters_position(-1)
         ,i_tags_position(-1)
+        ,i_tracks_position(-1)
+        ,i_attachments_position(-1)
         ,i_seekhead_position(-1)
+        ,i_seekhead_count(0)
         ,cluster(NULL)
         ,i_block_pos(0)
         ,i_cluster_pos(0)
@@ -1111,10 +1115,14 @@ public:
     std::vector<mkv_track_t*> tracks;
 
     /* from seekhead */
+    int                     i_seekhead_count;
+    int64_t                 i_seekhead_position;
     int64_t                 i_cues_position;
+    int64_t                 i_tracks_position;
+    int64_t                 i_info_position;
     int64_t                 i_chapters_position;
     int64_t                 i_tags_position;
-    int64_t                 i_seekhead_position;
+    int64_t                 i_attachments_position;
 
     KaxCluster              *cluster;
     uint64                  i_block_pos;
@@ -1150,6 +1158,7 @@ public:
     bool                           b_preloaded;
 
     bool Preload( );
+    bool LoadSeekHeadItem( const EbmlCallbacks & ClassInfos, int64_t i_element_position );
     bool PreloadFamily( const matroska_segment_c & segment );
     void ParseInfo( KaxInfo *info );
     void ParseAttachments( KaxAttachments *attachments );
@@ -1160,10 +1169,10 @@ public:
     void ParseTrackEntry( KaxTrackEntry *m );
     void ParseCluster( );
     void IndexAppendCluster( KaxCluster *cluster );
-    void LoadCues( );
-    void LoadTags( );
+    void LoadCues( KaxCues *cues );
+    void LoadTags( KaxTags *tags );
     void InformationCreate( );
-    void Seek( mtime_t i_date, mtime_t i_time_offset );
+    void Seek( mtime_t i_date, mtime_t i_time_offset, int64_t i_global_position );
 #if LIBMATROSKA_VERSION >= 0x000800
     int BlockGet( KaxBlock * &, KaxSimpleBlock * &, int64_t *, int64_t *, int64_t *);
 #else
@@ -1197,8 +1206,7 @@ public:
     size_t AddSegment( matroska_segment_c *p_segment );
     void PreloadLinked( );
     mtime_t Duration( ) const;
-    void LoadCues( );
-    void Seek( demux_t & demuxer, mtime_t i_date, mtime_t i_time_offset, chapter_item_c *psz_chapter );
+    void Seek( demux_t & demuxer, mtime_t i_date, mtime_t i_time_offset, chapter_item_c *psz_chapter, int64_t i_global_position );
 
     inline chapter_edition_c *Edition()
     {
@@ -1291,8 +1299,8 @@ typedef struct
     demux_t        *p_demux;
     vlc_mutex_t     lock;
 
-    bool      b_moved;
-    bool      b_clicked;
+    bool            b_moved;
+    bool            b_clicked;
     int             i_key_action;
 
 } event_thread_t;
@@ -1486,12 +1494,10 @@ static int Open( vlc_object_t * p_this )
     }
 
     p_segment = p_stream->segments[0];
-    if( p_segment->cluster != NULL )
+    if( p_segment->cluster == NULL )
     {
-        msg_Warn( p_demux, "cannot find any cluster, damaged file ?" );
-
-        // reset the stream reading to the first cluster of the segment used
-        p_stream->p_in->setFilePointer( p_segment->cluster->GetElementPosition() );
+        msg_Err( p_demux, "cannot find any cluster, damaged file ?" );
+        goto error;
     }
 
     if (config_GetInt( p_demux, "mkv-preload-local-dir" ))
@@ -1942,7 +1948,7 @@ static void BlockDecode( demux_t *p_demux, KaxBlock *block, mtime_t i_pts,
 
     size_t          i_track;
     unsigned int    i;
-    bool      b;
+    bool            b;
 
 #define tk  p_segment->tracks[i_track]
     for( i_track = 0; i_track < p_segment->tracks.size(); i_track++ )
@@ -3220,7 +3226,7 @@ bool virtual_segment_c::UpdateCurrentToChapter( demux_t & demux )
                 {
                     // only physically seek if necessary
                     if ( psz_current_chapter == NULL || (psz_current_chapter->i_end_time != psz_curr_chapter->i_start_time) )
-                        Seek( demux, sys.i_pts, 0, psz_curr_chapter );
+                        Seek( demux, sys.i_pts, 0, psz_curr_chapter, -1 );
                 }
             }
  
@@ -3441,6 +3447,7 @@ static void Seek( demux_t *p_demux, mtime_t i_date, double f_percent, chapter_it
     virtual_segment_c  *p_vsegment = p_sys->p_current_segment;
     matroska_segment_c *p_segment = p_vsegment->Segment();
     mtime_t            i_time_offset = 0;
+    int64_t            i_global_position = -1;
 
     int         i_index;
 
@@ -3459,7 +3466,7 @@ static void Seek( demux_t *p_demux, mtime_t i_date, double f_percent, chapter_it
     /* seek without index or without date */
     if( f_percent >= 0 && (config_GetInt( p_demux, "mkv-seek-percent" ) || !p_segment->b_cues || i_date < 0 ))
     {
-        if (p_sys->f_duration >= 0)
+        if( p_sys->f_duration >= 0 && p_segment->b_cues )
         {
             i_date = int64_t( f_percent * p_sys->f_duration * 1000.0 );
         }
@@ -3467,13 +3474,13 @@ static void Seek( demux_t *p_demux, mtime_t i_date, double f_percent, chapter_it
         {
             int64_t i_pos = int64_t( f_percent * stream_Size( p_demux->s ) );
 
-            msg_Dbg( p_demux, "inacurate way of seeking" );
+            msg_Dbg( p_demux, "inaccurate way of seeking for pos:%"PRId64, i_pos );
             for( i_index = 0; i_index < p_segment->i_index; i_index++ )
             {
-                if( p_segment->p_indexes[i_index].i_position >= i_pos)
-                {
+                if( p_segment->b_cues && p_segment->p_indexes[i_index].i_position < i_pos )
+                    break;
+                if( !p_segment->b_cues && p_segment->p_indexes[i_index].i_position >= i_pos && p_segment->p_indexes[i_index].i_time > 0 )
                     break;
-                }
             }
             if( i_index == p_segment->i_index )
             {
@@ -3482,37 +3489,15 @@ static void Seek( demux_t *p_demux, mtime_t i_date, double f_percent, chapter_it
 
             i_date = p_segment->p_indexes[i_index].i_time;
 
-#if 0
-            if( p_segment->p_indexes[i_index].i_position < i_pos )
+            if( !p_segment->b_cues && ( p_segment->p_indexes[i_index].i_position < i_pos || p_segment->p_indexes[i_index].i_position - i_pos > 2000000 ))
             {
-                EbmlElement *el;
-
-                msg_Warn( p_demux, "searching for cluster, could take some time" );
-
-                /* search a cluster */
-                while( ( el = p_sys->ep->Get() ) != NULL )
-                {
-                    if( MKV_IS_ID( el, KaxCluster ) )
-                    {
-                        KaxCluster *cluster = (KaxCluster*)el;
-
-                        /* add it to the index */
-                        p_segment->IndexAppendCluster( cluster );
-
-                        if( (int64_t)cluster->GetElementPosition() >= i_pos )
-                        {
-                            p_sys->cluster = cluster;
-                            p_sys->ep->Down();
-                            break;
-                        }
-                    }
-                }
+                msg_Dbg( p_demux, "no cues, seek request to global pos: %"PRId64, i_pos );
+                i_global_position = i_pos;
             }
-#endif
         }
     }
 
-    p_vsegment->Seek( *p_demux, i_date, i_time_offset, psz_chapter );
+    p_vsegment->Seek( *p_demux, i_date, i_time_offset, psz_chapter, i_global_position );
 }
 
 /*****************************************************************************
@@ -3932,34 +3917,15 @@ bool EbmlParser::IsTopPresent( EbmlElement *el )
  *  * InformationCreate : create all information, load tags if present
  *
  *****************************************************************************/
-void matroska_segment_c::LoadCues( )
+void matroska_segment_c::LoadCues( KaxCues *cues )
 {
-    int64_t     i_sav_position = es.I_O().getFilePointer();
     EbmlParser  *ep;
-    EbmlElement *el, *cues;
-
-    /* *** Load the cue if found *** */
-    if( i_cues_position < 0 )
-    {
-        msg_Warn( &sys.demuxer, "no cues/empty cues found->seek won't be precise" );
-
-//        IndexAppendCluster( cluster );
-    }
-
-    bool b_seekable;
-
-    stream_Control( sys.demuxer.s, STREAM_CAN_FASTSEEK, &b_seekable );
-    if( !b_seekable )
-        return;
-
-    msg_Dbg( &sys.demuxer, "loading cues" );
-    es.I_O().setFilePointer( i_cues_position, seek_beginning );
-    cues = es.FindNextID( KaxCues::ClassInfos, 0xFFFFFFFFL);
+    EbmlElement *el;
+    size_t i, j;
 
-    if( cues == NULL )
+    if( b_cues )
     {
-        msg_Err( &sys.demuxer, "cannot load cues (broken seekhead or file)" );
-        es.I_O().setFilePointer( i_sav_position, seek_beginning );
+        msg_Err( &sys.demuxer, "There can be only 1 Cues per section." );
         return;
     }
 
@@ -4047,33 +4013,19 @@ void matroska_segment_c::LoadCues( )
         }
     }
     delete ep;
-    delete cues;
-
     b_cues = true;
-
-    msg_Dbg( &sys.demuxer, "loading cues done." );
-    es.I_O().setFilePointer( i_sav_position, seek_beginning );
+    msg_Dbg( &sys.demuxer, "|   - loading cues done." );
 }
 
-void matroska_segment_c::LoadTags( )
+void matroska_segment_c::LoadTags( KaxTags *tags )
 {
-    int64_t     i_sav_position = es.I_O().getFilePointer();
     EbmlParser  *ep;
-    EbmlElement *el, *tags;
-
-    msg_Dbg( &sys.demuxer, "loading tags" );
-    es.I_O().setFilePointer( i_tags_position, seek_beginning );
-    tags = es.FindNextID( KaxTags::ClassInfos, 0xFFFFFFFFL);
-
-    if( tags == NULL )
-    {
-        msg_Err( &sys.demuxer, "cannot load tags (broken seekhead or file)" );
-        es.I_O().setFilePointer( i_sav_position, seek_beginning );
-        return;
-    }
+    EbmlElement *el;
+    size_t i, j;
 
-    msg_Dbg( &sys.demuxer, "Tags" );
+    /* Master elements */
     ep = new EbmlParser( &es, tags, &sys.demuxer );
+
     while( ( el = ep->Get() ) != NULL )
     {
         if( MKV_IS_ID( el, KaxTag ) )
@@ -4162,7 +4114,7 @@ void matroska_segment_c::LoadTags( )
                 }
                 else
                 {
-                    msg_Dbg( &sys.demuxer, "|   + Unknown (%s)", typeid( *el ).name() );
+                    msg_Dbg( &sys.demuxer, "|   + LoadTag Unknown (%s)", typeid( *el ).name() );
                 }
             }
             ep->Up();
@@ -4173,10 +4125,8 @@ void matroska_segment_c::LoadTags( )
         }
     }
     delete ep;
-    delete tags;
 
     msg_Dbg( &sys.demuxer, "loading tags done." );
-    es.I_O().setFilePointer( i_sav_position, seek_beginning );
 }
 
 /*****************************************************************************
@@ -4184,76 +4134,96 @@ void matroska_segment_c::LoadTags( )
  *****************************************************************************/
 void matroska_segment_c::ParseSeekHead( KaxSeekHead *seekhead )
 {
-    EbmlElement *el;
+    EbmlParser  *ep;
+    EbmlElement *l;
     size_t i, j;
     int i_upper_level = 0;
+    bool b_seekable;
 
-    msg_Dbg( &sys.demuxer, "|   + Seek head" );
+    i_seekhead_count++;
 
-    /* Master elements */
-    seekhead->Read( es, seekhead->Generic().Context, i_upper_level, el, true );
+    stream_Control( sys.demuxer.s, STREAM_CAN_SEEK, &b_seekable );
+    if( !b_seekable )
+        return;
 
-    for( i = 0; i < seekhead->ListSize(); i++ )
-    {
-        EbmlElement *l = (*seekhead)[i];
+    ep = new EbmlParser( &es, seekhead, &sys.demuxer );
 
+    while( ( l = ep->Get() ) != NULL )
+    {
         if( MKV_IS_ID( l, KaxSeek ) )
         {
-            EbmlMaster *sk = static_cast<EbmlMaster *>(l);
             EbmlId id = EbmlVoid::ClassInfos.GlobalId;
             int64_t i_pos = -1;
 
-            for( j = 0; j < sk->ListSize(); j++ )
+            msg_Dbg( &sys.demuxer, "|   |   + Seek" );
+            ep->Down();
+            while( ( l = ep->Get() ) != NULL )
             {
-                EbmlElement *l = (*sk)[j];
-
                 if( MKV_IS_ID( l, KaxSeekID ) )
                 {
                     KaxSeekID &sid = *(KaxSeekID*)l;
+                    sid.ReadData( es.I_O() );
                     id = EbmlId( sid.GetBuffer(), sid.GetSize() );
                 }
                 else if( MKV_IS_ID( l, KaxSeekPosition ) )
                 {
                     KaxSeekPosition &spos = *(KaxSeekPosition*)l;
-                    i_pos = uint64( spos );
+                    spos.ReadData( es.I_O() );
+                    i_pos = (int64_t)segment->GetGlobalPosition( uint64( spos ) );
                 }
                 else
                 {
-                    msg_Dbg( &sys.demuxer, "|   |   |   + Unknown (%s)", typeid(*l).name() );
+                    /* Many mkvmerge files hit this case. It seems to be a broken SeekHead */
+                    msg_Dbg( &sys.demuxer, "|   |   + Unknown (%s)", typeid(*l).name()  );
                 }
             }
+            ep->Up();
 
             if( i_pos >= 0 )
             {
                 if( id == KaxCues::ClassInfos.GlobalId )
                 {
-                    msg_Dbg( &sys.demuxer, "|   |   |   = cues at %"PRId64, i_pos );
-                    i_cues_position = segment->GetGlobalPosition( i_pos );
+                    msg_Dbg( &sys.demuxer, "|   - cues at %"PRId64, i_pos );
+                    LoadSeekHeadItem( KaxCues::ClassInfos, i_pos );
+                }
+                else if( id == KaxInfo::ClassInfos.GlobalId )
+                {
+                    msg_Dbg( &sys.demuxer, "|   - info at %"PRId64, i_pos );
+                    LoadSeekHeadItem( KaxInfo::ClassInfos, i_pos );
                 }
                 else if( id == KaxChapters::ClassInfos.GlobalId )
                 {
-                    msg_Dbg( &sys.demuxer, "|   |   |   = chapters at %"PRId64, i_pos );
-                    i_chapters_position = segment->GetGlobalPosition( i_pos );
+                    msg_Dbg( &sys.demuxer, "|   - chapters at %"PRId64, i_pos );
+                    LoadSeekHeadItem( KaxChapters::ClassInfos, i_pos );
                 }
                 else if( id == KaxTags::ClassInfos.GlobalId )
                 {
-                    msg_Dbg( &sys.demuxer, "|   |   |   = tags at %"PRId64, i_pos );
-                    i_tags_position = segment->GetGlobalPosition( i_pos );
+                    msg_Dbg( &sys.demuxer, "|   - tags at %"PRId64, i_pos );
+                    LoadSeekHeadItem( KaxTags::ClassInfos, i_pos );
                 }
                 else if( id == KaxSeekHead::ClassInfos.GlobalId )
                 {
-                    msg_Dbg( &sys.demuxer, "|   |   |   = seekhead at %"PRId64, i_pos );
-                    i_seekhead_position = segment->GetGlobalPosition( i_pos );
+                    msg_Dbg( &sys.demuxer, "|   - chained seekhead at %"PRId64, i_pos );
+                    LoadSeekHeadItem( KaxSeekHead::ClassInfos, i_pos );
+                }
+                else if( id == KaxTracks::ClassInfos.GlobalId )
+                {
+                    msg_Dbg( &sys.demuxer, "|   - tracks at %"PRId64, i_pos );
+                    LoadSeekHeadItem( KaxTracks::ClassInfos, i_pos );
+                }
+                else if( id == KaxAttachments::ClassInfos.GlobalId )
+                {
+                    msg_Dbg( &sys.demuxer, "|   - attachments at %"PRId64, i_pos );
+                    LoadSeekHeadItem( KaxAttachments::ClassInfos, i_pos );
                 }
                 else
-                    msg_Dbg( &sys.demuxer, "|   |   |   = unknown at %"PRId64, i_pos );
+                    msg_Dbg( &sys.demuxer, "|   - unknown seekhead reference at %"PRId64, i_pos );
             }
         }
         else
-        {
-            msg_Dbg( &sys.demuxer, "|   |   + Unknown (%s)", typeid(*l).name() );
-        }
+            msg_Dbg( &sys.demuxer, "|   |   + ParseSeekHead Unknown (%s)", typeid(*l).name() );
     }
+    delete ep;
 }
 
 /*****************************************************************************
@@ -4748,8 +4718,6 @@ void matroska_segment_c::ParseTracks( KaxTracks *tracks )
     unsigned int i;
     int i_upper_level = 0;
 
-    msg_Dbg( &sys.demuxer, "|   + Tracks" );
-
     /* Master elements */
     tracks->Read( es, tracks->Generic().Context, i_upper_level, el, true );
 
@@ -4778,8 +4746,6 @@ void matroska_segment_c::ParseInfo( KaxInfo *info )
     size_t i, j;
     int i_upper_level = 0;
 
-    msg_Dbg( &sys.demuxer, "|   + Information" );
-
     /* Master elements */
     m = static_cast<EbmlMaster *>(info);
     m->Read( es, info->Generic().Context, i_upper_level, el, true );
@@ -4870,7 +4836,7 @@ void matroska_segment_c::ParseInfo( KaxInfo *info )
 
             msg_Dbg( &sys.demuxer, "|   |   + family=%d", *(uint32*)uid->GetBuffer() );
         }
-#if defined( HAVE_GMTIME_R ) && !defined( __APPLE__ )
+#if defined( HAVE_GMTIME_R )
         else if( MKV_IS_ID( l, KaxDateUTC ) )
         {
             KaxDateUTC &date = *(KaxDateUTC*)l;
@@ -5079,7 +5045,9 @@ void matroska_segment_c::ParseAttachments( KaxAttachments *attachments )
 
         if( new_attachment )
         {
-            new_attachment->psz_file_name  = ToUTF8( UTFstring( file_name ) );
+            char* tmp = ToUTF8( UTFstring( file_name ) );
+            new_attachment->psz_file_name  = tmp;
+            free( tmp );
             new_attachment->psz_mime_type  = psz_mime_type;
             new_attachment->i_size         = img_data.GetSize();
             new_attachment->p_data         = malloc( img_data.GetSize() );
@@ -5236,7 +5204,7 @@ void matroska_segment_c::InformationCreate( )
         fprintf( stderr, "***** WARNING: Unhandled child meta\n");
     }
 #endif
-
+#if 0
     if( i_tags_position >= 0 )
     {
         bool b_seekable;
@@ -5247,6 +5215,7 @@ void matroska_segment_c::InformationCreate( )
             LoadTags( );
         }
     }
+#endif
 }
 
 
@@ -5525,13 +5494,13 @@ bool demux_sys_t::PreparePlayback( virtual_segment_c *p_new_segment )
         p_current_segment = p_new_segment;
         i_current_title = p_new_segment->i_sys_title;
     }
+    if( !p_current_segment->Segment()->b_cues )
+        msg_Warn( &p_current_segment->Segment()->sys.demuxer, "no cues/empty cues found->seek won't be precise" );
 
-    p_current_segment->LoadCues();
     f_duration = p_current_segment->Duration();
 
     /* add information */
     p_current_segment->Segment()->InformationCreate( );
-
     p_current_segment->Segment()->Select( 0 );
 
     return true;
@@ -5550,7 +5519,7 @@ void demux_sys_t::JumpTo( virtual_segment_c & vsegment, chapter_item_c * p_chapt
         if ( !p_chapter->Enter( true ) )
         {
             // jump to the location in the found segment
-            vsegment.Seek( demuxer, p_chapter->i_user_start_time, -1, p_chapter );
+            vsegment.Seek( demuxer, p_chapter->i_user_start_time, -1, p_chapter, -1 );
         }
     }
  
@@ -5594,26 +5563,44 @@ bool matroska_segment_c::Preload( )
 
     while( ( el = ep->Get() ) != NULL )
     {
-        if( MKV_IS_ID( el, KaxInfo ) )
+        if( MKV_IS_ID( el, KaxSeekHead ) )
         {
-            ParseInfo( static_cast<KaxInfo*>( el ) );
+            /* Multiple allowed */
+            /* We bail at 10, to prevent possible recursion */
+            msg_Dbg(  &sys.demuxer, "|   + Seek head" );
+            if( i_seekhead_count < 10 )
+            {
+                i_seekhead_position = (int64_t) es.I_O().getFilePointer();
+                ParseSeekHead( static_cast<KaxSeekHead*>( el ) );
+            }
+        }
+        else if( MKV_IS_ID( el, KaxInfo ) )
+        {
+            /* Multiple allowed, mandatory */
+            msg_Dbg(  &sys.demuxer, "|   + Information" );
+            if( i_info_position < 0 ) // FIXME
+                ParseInfo( static_cast<KaxInfo*>( el ) );
+            i_info_position = (int64_t) es.I_O().getFilePointer();
         }
         else if( MKV_IS_ID( el, KaxTracks ) )
         {
-            ParseTracks( static_cast<KaxTracks*>( el ) );
+            /* Multiple allowed */
+            msg_Dbg(  &sys.demuxer, "|   + Tracks" );
+            if( i_tracks_position < 0 ) // FIXME
+                ParseTracks( static_cast<KaxTracks*>( el ) );
             if ( tracks.size() == 0 )
             {
                 msg_Err( &sys.demuxer, "No tracks supported" );
                 return false;
             }
-        }
-        else if( MKV_IS_ID( el, KaxSeekHead ) )
-        {
-            ParseSeekHead( static_cast<KaxSeekHead*>( el ) );
+            i_tracks_position = (int64_t) es.I_O().getFilePointer();
         }
         else if( MKV_IS_ID( el, KaxCues ) )
         {
-            msg_Dbg( &sys.demuxer, "|   + Cues" );
+            msg_Dbg(  &sys.demuxer, "|   + Cues" );
+            if( i_cues_position < 0 )
+                LoadCues( static_cast<KaxCues*>( el ) );
+            i_cues_position = (int64_t) es.I_O().getFilePointer();
         }
         else if( MKV_IS_ID( el, KaxCluster ) )
         {
@@ -5625,27 +5612,32 @@ bool matroska_segment_c::Preload( )
             ParseCluster( );
 
             ep->Down();
-            /* stop parsing the stream */
+            /* stop pre-parsing the stream */
             break;
         }
         else if( MKV_IS_ID( el, KaxAttachments ) )
         {
             msg_Dbg( &sys.demuxer, "|   + Attachments" );
-            ParseAttachments( static_cast<KaxAttachments*>( el ) );
+            if( i_attachments_position < 0 )
+                ParseAttachments( static_cast<KaxAttachments*>( el ) );
+            i_attachments_position = (int64_t) es.I_O().getFilePointer();
         }
         else if( MKV_IS_ID( el, KaxChapters ) )
         {
             msg_Dbg( &sys.demuxer, "|   + Chapters" );
-            ParseChapters( static_cast<KaxChapters*>( el ) );
+            if( i_chapters_position < 0 )
+                ParseChapters( static_cast<KaxChapters*>( el ) );
+            i_chapters_position = (int64_t) es.I_O().getFilePointer();
         }
         else if( MKV_IS_ID( el, KaxTag ) )
         {
-            msg_Dbg( &sys.demuxer, "|   + Tags FIXME TODO" );
+            msg_Dbg( &sys.demuxer, "|   + Tags" );
+            if( i_tags_position < 0) // FIXME
+                ;//LoadTags( static_cast<KaxTags*>( el ) );
+            i_tags_position = (int64_t) es.I_O().getFilePointer();
         }
         else
-        {
-            msg_Dbg( &sys.demuxer, "|   + Unknown (%s)", typeid(*el).name() );
-        }
+            msg_Dbg( &sys.demuxer, "|   + Preload Unknown (%s)", typeid(*el).name() );
     }
 
     b_preloaded = true;
@@ -5653,6 +5645,93 @@ bool matroska_segment_c::Preload( )
     return true;
 }
 
+/* Here we try to load elements that were found in Seek Heads, but not yet parsed */
+bool matroska_segment_c::LoadSeekHeadItem( const EbmlCallbacks & ClassInfos, int64_t i_element_position )
+{
+    int64_t     i_sav_position = (int64_t)es.I_O().getFilePointer();
+    EbmlElement *el;
+
+    es.I_O().setFilePointer( i_element_position, seek_beginning );
+    el = es.FindNextID( ClassInfos, 0xFFFFFFFFL);
+
+    if( el == NULL )
+    {
+        msg_Err( &sys.demuxer, "cannot load some cues/chapters/tags etc. (broken seekhead or file)" );
+        es.I_O().setFilePointer( i_sav_position, seek_beginning );
+        return false;
+    }
+
+    if( MKV_IS_ID( el, KaxSeekHead ) )
+    {
+        /* Multiple allowed */
+        msg_Dbg( &sys.demuxer, "|   + Seek head" );
+        if( i_seekhead_count < 10 )
+        {
+            i_seekhead_position = i_element_position;
+            ParseSeekHead( static_cast<KaxSeekHead*>( el ) );
+        }
+    }
+    else if( MKV_IS_ID( el, KaxInfo ) ) // FIXME
+    {
+        /* Multiple allowed, mandatory */
+        msg_Dbg( &sys.demuxer, "|   + Information" );
+        if( i_info_position < 0 )
+            ParseInfo( static_cast<KaxInfo*>( el ) );
+        i_info_position = i_element_position;
+    }
+    else if( MKV_IS_ID( el, KaxTracks ) ) // FIXME
+    {
+        /* Multiple allowed */
+        msg_Dbg( &sys.demuxer, "|   + Tracks" );
+        if( i_tracks_position < 0 )
+            ParseTracks( static_cast<KaxTracks*>( el ) );
+        if ( tracks.size() == 0 )
+        {
+            msg_Err( &sys.demuxer, "No tracks supported" );
+            delete el;
+            es.I_O().setFilePointer( i_sav_position, seek_beginning );
+            return false;
+        }
+        i_tracks_position = i_element_position;
+    }
+    else if( MKV_IS_ID( el, KaxCues ) )
+    {
+        msg_Dbg( &sys.demuxer, "|   + Cues" );
+        if( i_cues_position < 0 )
+            LoadCues( static_cast<KaxCues*>( el ) );
+        i_cues_position = i_element_position;
+    }
+    else if( MKV_IS_ID( el, KaxAttachments ) )
+    {
+        msg_Dbg( &sys.demuxer, "|   + Attachments" );
+        if( i_attachments_position < 0 )
+            ParseAttachments( static_cast<KaxAttachments*>( el ) );
+        i_attachments_position = i_element_position;
+    }
+    else if( MKV_IS_ID( el, KaxChapters ) )
+    {
+        msg_Dbg( &sys.demuxer, "|   + Chapters" );
+        if( i_chapters_position < 0 )
+            ParseChapters( static_cast<KaxChapters*>( el ) );
+        i_chapters_position = i_element_position;
+    }
+    else if( MKV_IS_ID( el, KaxTag ) ) // FIXME
+    {
+        msg_Dbg( &sys.demuxer, "|   + Tags" );
+        if( i_tags_position < 0 )
+            ;//LoadTags( static_cast<KaxTags*>( el ) );
+        i_tags_position = i_element_position;
+    }
+    else
+    {
+        msg_Dbg( &sys.demuxer, "|   + LoadSeekHeadItem Unknown (%s)", typeid(*el).name() );
+    }
+    delete el;
+
+    es.I_O().setFilePointer( i_sav_position, seek_beginning );
+    return true;
+}
+
 matroska_segment_c *demux_sys_t::FindSegment( const EbmlBinary & uid ) const
 {
     for (size_t i=0; i<opened_segments.size(); i++)
@@ -5762,14 +5841,6 @@ mtime_t virtual_segment_c::Duration() const
     return i_duration;
 }
 
-void virtual_segment_c::LoadCues( )
-{
-    for ( size_t i=0; i<linked_segments.size(); i++ )
-    {
-        linked_segments[i]->LoadCues();
-    }
-}
-
 void virtual_segment_c::AppendUID( const EbmlBinary * p_UID )
 {
     if ( p_UID == NULL )
@@ -5785,7 +5856,7 @@ void virtual_segment_c::AppendUID( const EbmlBinary * p_UID )
     linked_uids.push_back( *(KaxSegmentUID*)(p_UID) );
 }
 
-void matroska_segment_c::Seek( mtime_t i_date, mtime_t i_time_offset )
+void matroska_segment_c::Seek( mtime_t i_date, mtime_t i_time_offset, int64_t i_global_position )
 {
     KaxBlock    *block;
 #if LIBMATROSKA_VERSION >= 0x000800
@@ -5799,6 +5870,39 @@ void matroska_segment_c::Seek( mtime_t i_date, mtime_t i_time_offset )
     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" );
+                    es_out_Control( sys.demuxer.out, ES_OUT_RESET_PCR );
+                    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;
@@ -5845,7 +5949,6 @@ void matroska_segment_c::Seek( mtime_t i_date, mtime_t i_time_offset )
         es_out_Control( sys.demuxer.out, ES_OUT_SET_NEXT_DISPLAY_TIME, tracks[i_track]->p_es, i_date );
     }
 
-
     while( i_track_skipping > 0 )
     {
 #if LIBMATROSKA_VERSION >= 0x000800
@@ -5921,7 +6024,7 @@ void matroska_segment_c::Seek( mtime_t i_date, mtime_t i_time_offset )
     }
 }
 
-void virtual_segment_c::Seek( demux_t & demuxer, mtime_t i_date, mtime_t i_time_offset, chapter_item_c *psz_chapter )
+void virtual_segment_c::Seek( demux_t & demuxer, mtime_t i_date, mtime_t i_time_offset, chapter_item_c *psz_chapter, int64_t i_global_position )
 {
     demux_sys_t *p_sys = demuxer.p_sys;
     size_t i;
@@ -5965,7 +6068,7 @@ void virtual_segment_c::Seek( demux_t & demuxer, mtime_t i_date, mtime_t i_time_
         i_current_segment = i;
     }
 
-    linked_segments[i]->Seek( i_date, i_time_offset );
+    linked_segments[i]->Seek( i_date, i_time_offset, i_global_position );
 }
 
 void chapter_codec_cmds_c::AddCommand( const KaxChapterProcessCommand & command )
@@ -6510,7 +6613,7 @@ bool dvd_command_interpretor_c::Interpret( const binary * p_command, size_t i_si
             {
                 if ( !p_chapter->Enter( true ) )
                     // jump to the location in the found segment
-                    sys.p_current_segment->Seek( sys.demuxer, p_chapter->i_user_start_time, -1, p_chapter );
+                    sys.p_current_segment->Seek( sys.demuxer, p_chapter->i_user_start_time, -1, p_chapter, -1 );
 
                 f_result = true;
             }
@@ -6528,7 +6631,7 @@ bool dvd_command_interpretor_c::Interpret( const binary * p_command, size_t i_si
             {
                 if ( !p_chapter->Enter( true ) )
                     // jump to the location in the found segment
-                    sys.p_current_segment->Seek( sys.demuxer, p_chapter->i_user_start_time, -1, p_chapter );
+                    sys.p_current_segment->Seek( sys.demuxer, p_chapter->i_user_start_time, -1, p_chapter, -1 );
 
                 f_result = true;
             }
@@ -6760,7 +6863,7 @@ bool matroska_script_interpretor_c::Interpret( const binary * p_command, size_t
         else
         {
             if ( !p_chapter->EnterAndLeave( sys.p_current_segment->CurrentChapter() ) )
-                p_segment->Seek( sys.demuxer, p_chapter->i_user_start_time, -1, p_chapter );
+                p_segment->Seek( sys.demuxer, p_chapter->i_user_start_time, -1, p_chapter, -1 );
             b_result = true;
         }
     }