[vlc-commits] MKV: find the duration in the last Cluster when it' s not in the Info header

Steve Lhomme git at videolan.org
Mon Feb 23 11:24:09 CET 2015


vlc | branch: master | Steve Lhomme <robux4 at gmail.com> | Mon Feb 23 11:02:26 2015 +0100| [16b3d6a450bb5c471a11fbb3e28e40284180e589] | committer: Jean-Baptiste Kempf

MKV: find the duration in the last Cluster when it's not in the Info header

Only on fast seeking sources

Close #12724

Signed-off-by: Jean-Baptiste Kempf <jb at videolan.org>

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

 modules/demux/mkv/matroska_segment.cpp |  104 ++++++++++++++++++++++++++++++++
 modules/demux/mkv/matroska_segment.hpp |    1 +
 2 files changed, 105 insertions(+)

diff --git a/modules/demux/mkv/matroska_segment.cpp b/modules/demux/mkv/matroska_segment.cpp
index 966d6aa..78d7f94 100644
--- a/modules/demux/mkv/matroska_segment.cpp
+++ b/modules/demux/mkv/matroska_segment.cpp
@@ -743,6 +743,8 @@ bool matroska_segment_c::Preload( )
 
     b_preloaded = true;
 
+    EnsureDuration();
+
     return true;
 }
 
@@ -1163,6 +1165,108 @@ void matroska_segment_c::ComputeTrackPriority()
     } 
 }
 
+void matroska_segment_c::EnsureDuration()
+{
+    if ( i_duration > 0 )
+        return;
+
+    i_duration = -1;
+
+    bool b_seekable;
+
+    stream_Control( sys.demuxer.s, STREAM_CAN_FASTSEEK, &b_seekable );
+    if ( !b_seekable )
+    {
+        msg_Warn( &sys.demuxer, "could not look for the segment duration" );
+        return;
+    }
+
+    uint64 i_current_position = es.I_O().getFilePointer();
+    uint64 i_last_cluster_pos = 0;
+
+    // find the last Cluster from the Cues
+    if ( b_cues && i_index > 0 && p_indexes != NULL)
+    {
+        i_last_cluster_pos = p_indexes[i_index-1].i_position;
+    }
+
+    // find the last Cluster manually
+    if ( !i_last_cluster_pos && cluster != NULL )
+    {
+        EbmlElement *el;
+        EbmlParser *ep;
+
+        es.I_O().setFilePointer( cluster->GetElementPosition(), seek_beginning );
+        ep = new EbmlParser( &es , segment, &sys.demuxer );
+
+        while( ( el = ep->Get() ) != NULL )
+        {
+            if ( MKV_IS_ID( el, KaxCluster ) )
+            {
+                i_last_cluster_pos = el->GetElementPosition();
+            }
+        }
+
+        delete ep;
+    }
+
+    // find the last timecode in the Cluster
+    if ( i_last_cluster_pos )
+    {
+        EbmlParser *ep;
+
+        es.I_O().setFilePointer( i_last_cluster_pos, seek_beginning );
+        ep = new EbmlParser( &es , segment, &sys.demuxer );
+
+        KaxCluster *p_last_cluster = (KaxCluster *) ep->Get();
+        ParseCluster( p_last_cluster, false, SCOPE_PARTIAL_DATA );
+
+        // use the last block + duration
+        uint64 i_last_timecode = p_last_cluster->GlobalTimecode();
+        for( unsigned int i = 0; i < p_last_cluster->ListSize(); i++ )
+        {
+            EbmlElement *l = (*p_last_cluster)[i];
+
+            if( MKV_IS_ID( l, KaxSimpleBlock ) )
+            {
+                KaxSimpleBlock *block = (KaxSimpleBlock*)l;
+                block->SetParent( *p_last_cluster );
+                i_last_timecode = max(i_last_timecode, block->GlobalTimecode());
+            }
+            else if( MKV_IS_ID( l, KaxBlockGroup ) )
+            {
+                KaxBlockGroup *group = (KaxBlockGroup*)l;
+                uint64 i_group_timecode = 0;
+                for( unsigned int j = 0; j < group->ListSize(); j++ )
+                {
+                    EbmlElement *l = (*group)[j];
+
+                    if( MKV_IS_ID( l, KaxBlock ) )
+                    {
+                        KaxBlock *block = (KaxBlock*)l;
+                        block->SetParent( *p_last_cluster );
+                        i_group_timecode += block->GlobalTimecode();
+                    }
+                    else if( MKV_IS_ID( l, KaxBlockDuration ) )
+                    {
+                        KaxBlockDuration & dur = *(KaxBlockDuration*)l;
+                        i_group_timecode += uint64( dur );
+                    }
+                }
+                i_last_timecode = max(i_last_timecode, i_group_timecode);
+            }
+        }
+
+        i_duration = ( i_last_timecode - cluster->GlobalTimecode() ) / (mtime_t)1000000;
+        msg_Dbg( &sys.demuxer, " extracted Duration=%" PRId64, i_duration );
+
+        delete ep;
+    }
+
+    // get back to the reading position we were at before looking for a duration
+    es.I_O().setFilePointer( i_current_position, seek_beginning );
+}
+
 bool matroska_segment_c::Select( mtime_t i_start_time )
 {
     /* add all es */
diff --git a/modules/demux/mkv/matroska_segment.hpp b/modules/demux/mkv/matroska_segment.hpp
index 3ef8e37..e29d8dd 100644
--- a/modules/demux/mkv/matroska_segment.hpp
+++ b/modules/demux/mkv/matroska_segment.hpp
@@ -163,6 +163,7 @@ private:
     void IndexAppendCluster( KaxCluster *cluster );
     int32_t TrackInit( mkv_track_t * p_tk );
     void ComputeTrackPriority();
+    void EnsureDuration();
 };
 
 



More information about the vlc-commits mailing list