[vlc-devel] [PATCH] MKV: find the duration in the Cluster when it's not set in the Info header

Jean-Baptiste Kempf jb at videolan.org
Fri Feb 20 19:21:16 CET 2015


I cannot apply this one either :"(

Le 20/02/2015 17:57, Steve Lhomme a écrit :
> Fixes #12724
>
> Use the Cues data to find the last Cluster, otherwise find the last
> Cluster by skipping over the whole file. Then look for the last
> timestamp (+ duration) in the Cluster, without reading the whole Block
> data.
>
> Only done on fast seeking sources.
>
> ---
>   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 df24096..ae70696 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();
>   };
>
>


-- 
Jean-Baptiste Kempf
http://www.jbkempf.com/ - +33 672 704 734
Sent from my Electronic Device



More information about the vlc-devel mailing list