[vlc-devel] [PATCH 10/30] mkv: replaced usage of std::vector with std::map (matroska_segment_c::tracks)

Filip Roséen filip at videolabs.io
Mon May 9 14:53:04 CEST 2016


Managing the tracks by a std::vector has been replaced with a std::map
mapping the track-number to a mkv_track_t.

This patch includes changing BlockFindTrackIndex to FindTrackByBlock,
keeping the same behaviour though using a more accurate name for the new
code.
---
 modules/demux/mkv/matroska_segment.cpp       | 145 ++++++++++++++-------------
 modules/demux/mkv/matroska_segment.hpp       |   6 +-
 modules/demux/mkv/matroska_segment_parse.cpp | 104 +++++++++++--------
 modules/demux/mkv/mkv.cpp                    | 140 ++++++++++++++++----------
 modules/demux/mkv/mkv.hpp                    |   1 +
 modules/demux/mkv/virtual_segment.cpp        |  81 ++++++++-------
 6 files changed, 267 insertions(+), 210 deletions(-)

diff --git a/modules/demux/mkv/matroska_segment.cpp b/modules/demux/mkv/matroska_segment.cpp
index b317079..017db2c 100644
--- a/modules/demux/mkv/matroska_segment.cpp
+++ b/modules/demux/mkv/matroska_segment.cpp
@@ -66,14 +66,14 @@ matroska_segment_c::matroska_segment_c( demux_sys_t & demuxer, EbmlStream & estr
 
 matroska_segment_c::~matroska_segment_c()
 {
-    for( size_t i_track = 0; i_track < tracks.size(); i_track++ )
+    for( tracks_map_t::iterator it = tracks.begin(); it != tracks.end(); ++it)
     {
-        delete tracks[i_track]->p_compression_data;
-        es_format_Clean( &tracks[i_track]->fmt );
-        delete tracks[i_track]->p_sys;
-        free( tracks[i_track]->p_extra_data );
-        free( tracks[i_track]->psz_codec );
-        delete tracks[i_track];
+        tracks_map_t::mapped_type& track = it->second;
+
+        es_format_Clean( &track.fmt );
+        delete track.p_compression_data;
+        delete track.p_sys;
+        free( track.p_extra_data );
     }
 
     free( psz_writing_application );
@@ -757,27 +757,25 @@ void matroska_segment_c::Seek( mtime_t i_mk_date, mtime_t i_mk_time_offset )
     // TODO: implement
 }
 
-int matroska_segment_c::BlockFindTrackIndex( size_t *pi_track,
+
+int matroska_segment_c::FindTrackByBlock(tracks_map_t::iterator* p_track_it,
                                              const KaxBlock *p_block, const KaxSimpleBlock *p_simpleblock )
 {
-    size_t i_track;
-    for( i_track = 0; i_track < tracks.size(); i_track++ )
-    {
-        const mkv_track_t *tk = tracks[i_track];
+    *p_track_it = tracks.end();
 
-        if( ( p_block != NULL && tk->i_number == p_block->TrackNum() ) ||
-            ( p_simpleblock != NULL && tk->i_number == p_simpleblock->TrackNum() ) )
-        {
-            break;
-        }
-    }
-
-    if( i_track >= tracks.size() )
+    if( p_block == NULL && p_simpleblock == NULL )
         return VLC_EGENERIC;
 
-    if( pi_track )
-        *pi_track = i_track;
-    return VLC_SUCCESS;
+    if (p_block != NULL)
+    {
+        *p_track_it = tracks.find( p_block->TrackNum() );
+    }
+    else if( p_simpleblock != NULL)
+    {
+        *p_track_it = tracks.find( p_simpleblock->TrackNum() );
+    }
+
+    return *p_track_it != tracks.end() ? VLC_SUCCESS : VLC_EGENERIC;
 }
 
 void matroska_segment_c::ComputeTrackPriority()
@@ -785,51 +783,52 @@ void matroska_segment_c::ComputeTrackPriority()
     bool b_has_default_video = false;
     bool b_has_default_audio = false;
     /* check for default */
-    for(size_t i_track = 0; i_track < tracks.size(); i_track++)
+    for( tracks_map_t::iterator it = tracks.begin(); it != tracks.end(); ++it )
     {
-        mkv_track_t *p_tk = tracks[i_track];
-        es_format_t *p_fmt = &p_tk->fmt;
-        if( p_fmt->i_cat == VIDEO_ES )
-            b_has_default_video |=
-                p_tk->b_enabled && ( p_tk->b_default || p_tk->b_forced );
-        else if( p_fmt->i_cat == AUDIO_ES )
-            b_has_default_audio |=
-                p_tk->b_enabled && ( p_tk->b_default || p_tk->b_forced );
+        tracks_map_t::mapped_type& track = it->second;
+
+        bool flag = track.b_enabled && ( track.b_default || track.b_forced );
+
+        switch( track.fmt.i_cat )
+        {
+            case VIDEO_ES: b_has_default_video |= flag; break;
+            case AUDIO_ES: b_has_default_audio |= flag; break;
+        }
     }
 
-    for( size_t i_track = 0; i_track < tracks.size(); i_track++ )
+    for( tracks_map_t::iterator it = tracks.begin(); it != tracks.end(); ++it )
     {
-        mkv_track_t *p_tk = tracks[i_track];
-        es_format_t *p_fmt = &p_tk->fmt;
+        tracks_map_t::key_type    track_id = it->first;
+        tracks_map_t::mapped_type track    = it->second;
 
-        if( unlikely( p_fmt->i_cat == UNKNOWN_ES || !p_tk->psz_codec ) )
+        if( unlikely( track.fmt.i_cat == UNKNOWN_ES || !track.psz_codec ) )
         {
-            msg_Warn( &sys.demuxer, "invalid track[%d, n=%d]", static_cast<int>( i_track ), p_tk->i_number );
-            p_tk->p_es = NULL;
+            msg_Warn( &sys.demuxer, "invalid track[%d]", static_cast<int>( track_id ) );
+            track.p_es = NULL;
             continue;
         }
-        else if( unlikely( !b_has_default_video && p_fmt->i_cat == VIDEO_ES ) )
+        else if( unlikely( !b_has_default_video && track.fmt.i_cat == VIDEO_ES ) )
         {
-            p_tk->b_default = true;
+            track.b_default = true;
             b_has_default_video = true;
         }
-        else if( unlikely( !b_has_default_audio &&  p_fmt->i_cat == AUDIO_ES ) )
+        else if( unlikely( !b_has_default_audio &&  track.fmt.i_cat == AUDIO_ES ) )
         {
-            p_tk->b_default = true;
+            track.b_default = true;
             b_has_default_audio = true;
         }
-        if( unlikely( !p_tk->b_enabled ) )
-            p_tk->fmt.i_priority = ES_PRIORITY_NOT_SELECTABLE;
-        else if( p_tk->b_forced )
-            p_tk->fmt.i_priority = ES_PRIORITY_SELECTABLE_MIN + 2;
-        else if( p_tk->b_default )
-            p_tk->fmt.i_priority = ES_PRIORITY_SELECTABLE_MIN + 1;
+        if( unlikely( !track.b_enabled ) )
+            track.fmt.i_priority = ES_PRIORITY_NOT_SELECTABLE;
+        else if( track.b_forced )
+            track.fmt.i_priority = ES_PRIORITY_SELECTABLE_MIN + 2;
+        else if( track.b_default )
+            track.fmt.i_priority = ES_PRIORITY_SELECTABLE_MIN + 1;
         else
-            p_tk->fmt.i_priority = ES_PRIORITY_SELECTABLE_MIN;
+            track.fmt.i_priority = ES_PRIORITY_SELECTABLE_MIN;
 
         /* Avoid multivideo tracks when unnecessary */
-        if( p_tk->fmt.i_cat == VIDEO_ES )
-            p_tk->fmt.i_priority--;
+        if( track.fmt.i_cat == VIDEO_ES )
+            track.fmt.i_priority--;
     }
 }
 
@@ -932,31 +931,29 @@ bool matroska_segment_c::Select( mtime_t i_mk_start_time )
     /* add all es */
     msg_Dbg( &sys.demuxer, "found %d es", static_cast<int>( tracks.size() ) );
 
-    for( size_t i_track = 0; i_track < tracks.size(); i_track++ )
+    for( tracks_map_t::iterator it = tracks.begin(); it != tracks.end(); ++it )
     {
-        mkv_track_t *p_tk = tracks[i_track];
-        es_format_t *p_fmt = &p_tk->fmt;
+        tracks_map_t::key_type     track_id = it->first;
+        tracks_map_t::mapped_type& track    = it->second;
 
-        if( unlikely( p_fmt->i_cat == UNKNOWN_ES || !p_tk->psz_codec ) )
+        if( unlikely( track.fmt.i_cat == UNKNOWN_ES || !track.psz_codec ) )
         {
-            msg_Warn( &sys.demuxer, "invalid track[%d, n=%d]", static_cast<int>( i_track ), p_tk->i_number );
-            p_tk->p_es = NULL;
+            msg_Warn( &sys.demuxer, "invalid track[%d]", static_cast<int>( track_id ) );
+            track.p_es = NULL;
             continue;
         }
 
-        if( !p_tk->p_es )
-            p_tk->p_es = es_out_Add( sys.demuxer.out, &p_tk->fmt );
+        if( !track.p_es )
+            track.p_es = es_out_Add( sys.demuxer.out, &track.fmt );
 
         /* Turn on a subtitles track if it has been flagged as default -
          * but only do this if no subtitles track has already been engaged,
          * either by an earlier 'default track' (??) or by default
          * language choice behaviour.
          */
-        if( p_tk->b_default || p_tk->b_forced )
+        if( track.b_default || track.b_forced )
         {
-            es_out_Control( sys.demuxer.out,
-                            ES_OUT_SET_ES_DEFAULT,
-                            p_tk->p_es );
+            es_out_Control( sys.demuxer.out, ES_OUT_SET_ES_DEFAULT, track.p_es );
         }
     }
     es_out_Control( sys.demuxer.out, ES_OUT_SET_NEXT_DISPLAY_TIME, i_mk_start_time );
@@ -973,27 +970,33 @@ bool matroska_segment_c::Select( mtime_t i_mk_start_time )
 void matroska_segment_c::UnSelect( )
 {
     sys.p_ev->ResetPci();
-    for( size_t i_track = 0; i_track < tracks.size(); i_track++ )
+
+    for( tracks_map_t::iterator it = tracks.begin(); it != tracks.end(); ++it )
     {
-        if ( tracks[i_track]->p_es != NULL )
+        tracks_map_t::mapped_type& track = it->second;
+
+        if( track.p_es != NULL )
         {
-//            es_format_Clean( &tracks[i_track]->fmt );
-            es_out_Del( sys.demuxer.out, tracks[i_track]->p_es );
-            tracks[i_track]->p_es = NULL;
+            es_out_Del( sys.demuxer.out, track.p_es );
+            track.p_es = NULL;
         }
     }
+
+    /* TODO: we will leak, fix this!
     delete ep;
     ep = NULL;
+    */
 }
 
 int matroska_segment_c::BlockGet( KaxBlock * & pp_block, KaxSimpleBlock * & pp_simpleblock, bool *pb_key_picture, bool *pb_discardable_picture, int64_t *pi_duration )
 {
+    tracks_map_t::iterator track_it;
+
     pp_simpleblock = NULL;
     pp_block = NULL;
 
     *pb_key_picture         = true;
     *pb_discardable_picture = false;
-    size_t i_tk;
     *pi_duration = 0;
 
     struct BlockPayload {
@@ -1136,7 +1139,7 @@ int matroska_segment_c::BlockGet( KaxBlock * & pp_block, KaxSimpleBlock * & pp_s
         if( pp_simpleblock != NULL || ((el = ep->Get()) == NULL && pp_block != NULL) )
         {
             /* Check blocks validity to protect againts broken files */
-            if( BlockFindTrackIndex( &i_tk, pp_block , pp_simpleblock ) )
+            if( FindTrackByBlock( &track_it, pp_block , pp_simpleblock ) )
             {
                 ep->Unkeep();
                 pp_simpleblock = NULL;
@@ -1151,7 +1154,7 @@ int matroska_segment_c::BlockGet( KaxBlock * & pp_block, KaxSimpleBlock * & pp_s
             /* We have block group let's check if the picture is a keyframe */
             else if( *pb_key_picture )
             {
-                if( tracks[i_tk]->fmt.i_codec == VLC_CODEC_THEORA )
+                if( track_it->second.fmt.i_codec == VLC_CODEC_THEORA )
                 {
                     DataBuffer *    p_data = &pp_block->GetBuffer(0);
                     const uint8_t * p_buff = p_data->Buffer();
diff --git a/modules/demux/mkv/matroska_segment.hpp b/modules/demux/mkv/matroska_segment.hpp
index 2672f9a..a653d76 100644
--- a/modules/demux/mkv/matroska_segment.hpp
+++ b/modules/demux/mkv/matroska_segment.hpp
@@ -71,6 +71,7 @@ public:
 class matroska_segment_c
 {
 public:
+    typedef std::map<mkv_track_t::track_id_t, mkv_track_t> tracks_map_t;
     typedef std::vector<Tag>            tags_t;
 
     matroska_segment_c( demux_sys_t & demuxer, EbmlStream & estream );
@@ -87,7 +88,7 @@ public:
     mtime_t                 i_mk_start_time;
 
     /* all tracks */
-    std::vector<mkv_track_t*> tracks;
+    tracks_map_t tracks;
 
     /* from seekhead */
     int                     i_seekhead_count;
@@ -136,12 +137,11 @@ public:
     void Seek( mtime_t i_mk_date, mtime_t i_mk_time_offset );
     int BlockGet( KaxBlock * &, KaxSimpleBlock * &, bool *, bool *, int64_t *);
 
-    int BlockFindTrackIndex( size_t *pi_track,
-                             const KaxBlock *, const KaxSimpleBlock * );
 
     bool Select( mtime_t i_mk_start_time );
     void UnSelect();
 
+    int FindTrackByBlock(tracks_map_t::iterator* track_it, const KaxBlock *, const KaxSimpleBlock * );
 
 
     static bool CompareSegmentUIDs( const matroska_segment_c * item_a, const matroska_segment_c * item_b );
diff --git a/modules/demux/mkv/matroska_segment_parse.cpp b/modules/demux/mkv/matroska_segment_parse.cpp
index e128ad3..c8c6b60 100644
--- a/modules/demux/mkv/matroska_segment_parse.cpp
+++ b/modules/demux/mkv/matroska_segment_parse.cpp
@@ -39,6 +39,7 @@ extern "C" {
 
 #include <vlc_codecs.h>
 #include <stdexcept>
+#include <limits>
 
 /* GetFourCC helper */
 #define GetFOURCC( p )  __GetFOURCC( (uint8_t*)p )
@@ -200,33 +201,53 @@ void matroska_segment_c::ParseTrackEntry( KaxTrackEntry *m )
     bool bSupported = true;
 
     /* Init the track */
-    mkv_track_t *tk = new mkv_track_t();
-    memset( tk, 0, sizeof( mkv_track_t ) );
-
-    es_format_Init( &tk->fmt, UNKNOWN_ES, 0 );
-    tk->p_es = NULL;
-    tk->fmt.psz_language       = strdup("English");
-    tk->fmt.psz_description    = NULL;
-
-    tk->b_default              = true;
-    tk->b_enabled              = true;
-    tk->b_forced               = false;
-    tk->i_number               = tracks.size() - 1;
-    tk->i_extra_data           = 0;
-    tk->p_extra_data           = NULL;
-    tk->psz_codec              = NULL;
-    tk->b_dts_only             = false;
-    tk->i_default_duration     = 0;
-    tk->b_no_duration          = false;
-    tk->f_timecodescale        = 1.0;
-
-    tk->b_inited               = false;
-    tk->i_data_init            = 0;
-    tk->p_data_init            = NULL;
-
-    tk->i_compression_type     = MATROSKA_COMPRESSION_NONE;
-    tk->i_encoding_scope       = MATROSKA_ENCODING_SCOPE_ALL_FRAMES;
-    tk->p_compression_data     = NULL;
+    mkv_track_t track;
+
+    track.fmt.psz_language       = strdup("English");
+    track.fmt.psz_description    = NULL;
+
+    track.b_default              = true;
+    track.b_enabled              = true;
+    track.b_forced               = false;
+    track.i_number               = 0;
+
+    track.i_extra_data           = 0;
+    track.p_extra_data           = NULL;
+
+    track.psz_codec              = NULL;
+    track.b_dts_only             = false;
+    track.b_pts_only             = false;
+
+    track.b_no_duration          = false;
+    track.i_default_duration     = 0;
+    track.f_timecodescale        = 1.0;
+    track.i_last_dts             = 0;
+    track.i_skip_until_fpos      = -1;
+
+    std::memset(    &track.fmt, 0, sizeof( track.fmt ) );
+    es_format_Init( &track.fmt, UNKNOWN_ES, 0 );
+    track.f_fps = 0;
+    track.p_es = NULL;
+
+    track.i_original_rate        = 0;
+    track.i_chans_to_reorder     = 0;
+    std::memset( &track.pi_chan_table, 0, sizeof( track.pi_chan_table ) );
+
+    track.p_sys                  = NULL;
+
+    track.b_inited               = false;
+
+    track.i_data_init            = 0;
+    track.p_data_init            = NULL;
+
+    track.str_codec_name         = "";
+
+    track.i_compression_type     = MATROSKA_COMPRESSION_NONE;
+    track.i_encoding_scope       = MATROSKA_ENCODING_SCOPE_ALL_FRAMES;
+    track.p_compression_data     = NULL;
+
+    track.i_seek_preroll          = 0;
+    track.i_codec_delay           = 0;
 
     MkvTree( sys.demuxer, 2, "Track Entry" );
 
@@ -247,7 +268,7 @@ void matroska_segment_c::ParseTrackEntry( KaxTrackEntry *m )
       } track_video_info;
 
     } metadata_payload = {
-      this, tk, &sys.demuxer, bSupported, 3, { }
+      this, &track, &sys.demuxer, bSupported, 3, { }
     };
 
     MKV_SWITCH_CREATE( EbmlTypeDispatcher, MetaDataHandlers, MetaDataCapture )
@@ -603,31 +624,34 @@ void matroska_segment_c::ParseTrackEntry( KaxTrackEntry *m )
 
     MetaDataHandlers::Dispatcher().iterate ( m->begin(), m->end(), MetaDataHandlers::Payload( metadata_payload ) );
 
+    if( track.i_number == 0 )
+    {
+        msg_Warn( &sys.demuxer, "Missing KaxTrackNumber, discarding track!" );
+        return;
+    }
 
     if ( bSupported )
     {
 #ifdef HAVE_ZLIB_H
-        if( tk->i_compression_type == MATROSKA_COMPRESSION_ZLIB &&
-            tk->i_encoding_scope & MATROSKA_ENCODING_SCOPE_PRIVATE &&
-            tk->i_extra_data && tk->p_extra_data &&
-            zlib_decompress_extra( &sys.demuxer, tk) )
+        if( track.i_compression_type == MATROSKA_COMPRESSION_ZLIB &&
+            track.i_encoding_scope & MATROSKA_ENCODING_SCOPE_PRIVATE &&
+            track.i_extra_data && track.p_extra_data &&
+            zlib_decompress_extra( &sys.demuxer, &track ) )
             return;
 #endif
-        if( TrackInit( tk ) )
+        if( TrackInit( &track ) )
         {
-            msg_Err(&sys.demuxer, "Couldn't init track %d", tk->i_number );
-            free(tk->p_extra_data);
-            delete tk;
+            msg_Err(&sys.demuxer, "Couldn't init track %d", track.i_number );
+            free(track.p_extra_data);
             return;
         }
 
-        tracks.push_back( tk );
+        tracks.insert( std::make_pair( track.i_number, track ) ); // TODO: add warning if two tracks have the same key
     }
     else
     {
-        msg_Err( &sys.demuxer, "Track Entry %d not supported", tk->i_number );
-        free(tk->p_extra_data);
-        delete tk;
+        msg_Err( &sys.demuxer, "Track Entry %d not supported", track.i_number );
+        free(track.p_extra_data);
     }
 }
 
diff --git a/modules/demux/mkv/mkv.cpp b/modules/demux/mkv/mkv.cpp
index 3da89bf..7323b42 100644
--- a/modules/demux/mkv/mkv.cpp
+++ b/modules/demux/mkv/mkv.cpp
@@ -418,13 +418,16 @@ static int Control( demux_t *p_demux, int i_query, va_list args )
             *pf = 0.0;
             if( p_sys->p_current_vsegment && p_sys->p_current_vsegment->CurrentSegment() )
             {
+                typedef matroska_segment_c::tracks_map_t tracks_map_t;
+
                 const matroska_segment_c *p_segment = p_sys->p_current_vsegment->CurrentSegment();
-                for( size_t i = 0; i < p_segment->tracks.size(); i++ )
+                for( tracks_map_t::const_iterator it = p_segment->tracks.begin(); it != p_segment->tracks.end(); ++it )
                 {
-                    mkv_track_t *tk = p_segment->tracks[i];
-                    if( tk->fmt.i_cat == VIDEO_ES && tk->fmt.video.i_frame_rate_base > 0 )
+                    tracks_map_t::mapped_type const& track = it->second;
+
+                    if( track.fmt.i_cat == VIDEO_ES && track.fmt.video.i_frame_rate_base > 0 )
                     {
-                        *pf = (double)tk->fmt.video.i_frame_rate / tk->fmt.video.i_frame_rate_base;
+                        *pf = (double)track.fmt.video.i_frame_rate / track.fmt.video.i_frame_rate_base;
                         break;
                     }
                 }
@@ -491,53 +494,56 @@ void BlockDecode( demux_t *p_demux, KaxBlock *block, KaxSimpleBlock *simpleblock
                   mtime_t i_pts, mtime_t i_duration, bool b_key_picture,
                   bool b_discardable_picture )
 {
+    typedef matroska_segment_c::tracks_map_t tracks_map_t;
+
     demux_sys_t        *p_sys = p_demux->p_sys;
     matroska_segment_c *p_segment = p_sys->p_current_vsegment->CurrentSegment();
 
     if( !p_segment ) return;
 
-    size_t          i_track;
-    if( p_segment->BlockFindTrackIndex( &i_track, block, simpleblock ) )
+    tracks_map_t::iterator track_it;
+
+    if( p_segment->FindTrackByBlock( &track_it, block, simpleblock ) )
     {
         msg_Err( p_demux, "invalid track number" );
         return;
     }
 
-    mkv_track_t *tk = p_segment->tracks[i_track];
+    tracks_map_t::mapped_type& track = track_it->second;
 
-    if( tk->fmt.i_cat != NAV_ES && tk->p_es == NULL )
+    if( track.fmt.i_cat != NAV_ES && track.p_es == NULL )
     {
         msg_Err( p_demux, "unknown track number" );
         return;
     }
 
-    i_pts -= tk->i_codec_delay;
+    i_pts -= track.i_codec_delay;
 
-    if ( tk->fmt.i_cat != NAV_ES )
+    if ( track.fmt.i_cat != NAV_ES )
     {
         bool b;
-        es_out_Control( p_demux->out, ES_OUT_GET_ES_STATE, tk->p_es, &b );
+        es_out_Control( p_demux->out, ES_OUT_GET_ES_STATE, track.p_es, &b );
 
         if( !b )
         {
-            tk->b_inited = false;
-            if( tk->fmt.i_cat == VIDEO_ES || tk->fmt.i_cat == AUDIO_ES )
-                tk->i_last_dts = VLC_TS_INVALID;
+            track.b_inited = false;
+            if( track.fmt.i_cat == VIDEO_ES || track.fmt.i_cat == AUDIO_ES )
+                track.i_last_dts = VLC_TS_INVALID;
             return;
         }
     }
 
 
     /* First send init data */
-    if( !tk->b_inited && tk->i_data_init > 0 )
+    if( !track.b_inited && track.i_data_init > 0 )
     {
         block_t *p_init;
 
-        msg_Dbg( p_demux, "sending header (%d bytes)", tk->i_data_init );
-        p_init = MemToBlock( tk->p_data_init, tk->i_data_init, 0 );
-        if( p_init ) send_Block( p_demux, tk, p_init, 1, 0 );
+        msg_Dbg( p_demux, "sending header (%d bytes)", track.i_data_init );
+        p_init = MemToBlock( track.p_data_init, track.i_data_init, 0 );
+        if( p_init ) send_Block( p_demux, &track, p_init, 1, 0 );
     }
-    tk->b_inited = true;
+    track.b_inited = true;
 
 
     size_t frame_size = 0;
@@ -569,12 +575,12 @@ void BlockDecode( demux_t *p_demux, KaxBlock *block, KaxSimpleBlock *simpleblock
             break;
         }
 
-        if( tk->i_compression_type == MATROSKA_COMPRESSION_HEADER &&
-            tk->p_compression_data != NULL &&
-            tk->i_encoding_scope & MATROSKA_ENCODING_SCOPE_ALL_FRAMES )
-            p_block = MemToBlock( data->Buffer(), data->Size(), tk->p_compression_data->GetSize() );
-        else if( unlikely( tk->fmt.i_codec == VLC_CODEC_WAVPACK ) )
-            p_block = packetize_wavpack(tk, data->Buffer(), data->Size());
+        if( track.i_compression_type == MATROSKA_COMPRESSION_HEADER &&
+            track.p_compression_data != NULL &&
+            track.i_encoding_scope & MATROSKA_ENCODING_SCOPE_ALL_FRAMES )
+            p_block = MemToBlock( data->Buffer(), data->Size(), track.p_compression_data->GetSize() );
+        else if( unlikely( track.fmt.i_codec == VLC_CODEC_WAVPACK ) )
+            p_block = packetize_wavpack( &track, data->Buffer(), data->Size() );
         else
             p_block = MemToBlock( data->Buffer(), data->Size(), 0 );
 
@@ -584,8 +590,8 @@ void BlockDecode( demux_t *p_demux, KaxBlock *block, KaxSimpleBlock *simpleblock
         }
 
 #if defined(HAVE_ZLIB_H)
-        if( tk->i_compression_type == MATROSKA_COMPRESSION_ZLIB &&
-            tk->i_encoding_scope & MATROSKA_ENCODING_SCOPE_ALL_FRAMES )
+        if( track.i_compression_type == MATROSKA_COMPRESSION_ZLIB &&
+            track.i_encoding_scope & MATROSKA_ENCODING_SCOPE_ALL_FRAMES )
         {
             p_block = block_zlib_decompress( VLC_OBJECT(p_demux), p_block );
             if( p_block == NULL )
@@ -593,24 +599,24 @@ void BlockDecode( demux_t *p_demux, KaxBlock *block, KaxSimpleBlock *simpleblock
         }
         else
 #endif
-        if( tk->i_compression_type == MATROSKA_COMPRESSION_HEADER &&
-            tk->i_encoding_scope & MATROSKA_ENCODING_SCOPE_ALL_FRAMES )
+        if( track.i_compression_type == MATROSKA_COMPRESSION_HEADER &&
+            track.i_encoding_scope & MATROSKA_ENCODING_SCOPE_ALL_FRAMES )
         {
-            memcpy( p_block->p_buffer, tk->p_compression_data->GetBuffer(), tk->p_compression_data->GetSize() );
+            memcpy( p_block->p_buffer, track.p_compression_data->GetBuffer(), track.p_compression_data->GetSize() );
         }
 
         if ( b_key_picture )
             p_block->i_flags |= BLOCK_FLAG_TYPE_I;
 
-        switch( tk->fmt.i_codec )
+        switch( track.fmt.i_codec )
         {
         case VLC_CODEC_COOK:
         case VLC_CODEC_ATRAC3:
         {
-            handle_real_audio(p_demux, tk, p_block, i_pts);
+            handle_real_audio(p_demux, &track, p_block, i_pts);
             block_Release(p_block);
-            i_pts = ( tk->i_default_duration )?
-                i_pts + ( mtime_t )tk->i_default_duration:
+            i_pts = ( track.i_default_duration )?
+                i_pts + ( mtime_t )track.i_default_duration:
                 VLC_TS_INVALID;
             continue;
          }
@@ -629,17 +635,17 @@ void BlockDecode( demux_t *p_demux, KaxBlock *block, KaxSimpleBlock *simpleblock
             break;
 
          case VLC_CODEC_OPUS:
-            mtime_t i_length = i_duration * tk-> f_timecodescale *
+            mtime_t i_length = i_duration * track. f_timecodescale *
                     (double) p_segment->i_timescale / 1000.0;
             if ( i_length < 0 ) i_length = 0;
-            p_block->i_nb_samples = i_length * tk->fmt.audio.i_rate
+            p_block->i_nb_samples = i_length * track.fmt.audio.i_rate
                     / CLOCK_FREQ;
             break;
         }
 
-        if( tk->fmt.i_cat != VIDEO_ES )
+        if( track.fmt.i_cat != VIDEO_ES )
         {
-            if ( tk->fmt.i_cat == NAV_ES )
+            if ( track.fmt.i_cat == NAV_ES )
             {
                 // TODO handle the start/stop times of this packet
                 p_sys->p_ev->SetPci( (const pci_t *)&p_block->p_buffer[1]);
@@ -651,12 +657,12 @@ void BlockDecode( demux_t *p_demux, KaxBlock *block, KaxSimpleBlock *simpleblock
         else
         {
             // correct timestamping when B frames are used
-            if( tk->b_dts_only )
+            if( track.b_dts_only )
             {
                 p_block->i_pts = VLC_TS_INVALID;
                 p_block->i_dts = i_pts;
             }
-            else if( tk->b_pts_only )
+            else if( track.b_pts_only )
             {
                 p_block->i_pts = i_pts;
                 p_block->i_dts = i_pts;
@@ -666,20 +672,20 @@ void BlockDecode( demux_t *p_demux, KaxBlock *block, KaxSimpleBlock *simpleblock
                 p_block->i_pts = i_pts;
                 // condition when the DTS is correct (keyframe or B frame == NOT P frame)
                 if ( b_key_picture || b_discardable_picture )
-                    p_block->i_dts = p_block->i_pts;
-                else if ( tk->i_last_dts == VLC_TS_INVALID )
+                        p_block->i_dts = p_block->i_pts;
+                else if ( track.i_last_dts == VLC_TS_INVALID )
                     p_block->i_dts = i_pts;
                 else
-                    p_block->i_dts = std::min( i_pts, tk->i_last_dts + ( mtime_t )tk->i_default_duration );
+                    p_block->i_dts = std::min( i_pts, track.i_last_dts + ( mtime_t )track.i_default_duration );
             }
         }
 
-        send_Block( p_demux, tk, p_block, i_number_frames, i_duration );
+        send_Block( p_demux, &track, p_block, i_number_frames, i_duration );
 
         /* use time stamp only for first block */
-        i_pts = ( tk->i_default_duration )?
-                 i_pts + ( mtime_t )tk->i_default_duration:
-                 ( tk->fmt.b_packetized ) ? VLC_TS_INVALID : i_pts + 1;
+        i_pts = ( track.i_default_duration )?
+                 i_pts + ( mtime_t )track.i_default_duration:
+                 ( track.fmt.b_packetized ) ? VLC_TS_INVALID : i_pts + 1;
     }
 }
 
@@ -739,16 +745,40 @@ static int Demux( demux_t *p_demux)
         p_sys->i_pts = (mtime_t)block->GlobalTimecode() / INT64_C(1000);
     p_sys->i_pts += p_sys->i_mk_chapter_time + VLC_TS_0;
 
-    mtime_t i_pcr = VLC_TS_INVALID;
-    for( size_t i = 0; i < p_segment->tracks.size(); i++)
-        if( p_segment->tracks[i]->i_last_dts > VLC_TS_INVALID &&
-            ( p_segment->tracks[i]->i_last_dts < i_pcr || i_pcr == VLC_TS_INVALID ))
-            i_pcr = p_segment->tracks[i]->i_last_dts;
 
-    if( i_pcr > p_sys->i_pcr + 300000 )
+
+    /* update pcr */
     {
-        es_out_Control( p_demux->out, ES_OUT_SET_PCR, VLC_TS_0 + p_sys->i_pcr );
-        p_sys->i_pcr = i_pcr;
+        int64_t i_pcr = VLC_TS_INVALID;
+
+        typedef matroska_segment_c::tracks_map_t tracks_map_t;
+
+        for( tracks_map_t::iterator it = p_segment->tracks.begin(); it != p_segment->tracks.end(); ++it )
+        {
+            tracks_map_t::mapped_type& track = it->second;
+      
+            if( track.i_last_dts == VLC_TS_INVALID )
+                continue;
+
+            if( track.fmt.i_cat != VIDEO_ES && track.fmt.i_cat != AUDIO_ES )
+                continue;
+
+            if( track.i_last_dts < i_pcr || i_pcr <= VLC_TS_INVALID )
+            {
+                i_pcr = track.i_last_dts;
+            }
+        }
+
+        if( i_pcr > VLC_TS_INVALID && i_pcr > p_sys->i_pcr )
+        {
+            if( es_out_Control( p_demux->out, ES_OUT_SET_PCR, i_pcr ) )
+            {
+                msg_Err( p_demux, "ES_OUT_SET_PCR failed, aborting." );
+                return 0;
+            }
+
+            p_sys->i_pcr = i_pcr;
+        }
     }
 
     if ( p_vsegment->CurrentEdition() &&
diff --git a/modules/demux/mkv/mkv.hpp b/modules/demux/mkv/mkv.hpp
index b428266..8bad7dc 100644
--- a/modules/demux/mkv/mkv.hpp
+++ b/modules/demux/mkv/mkv.hpp
@@ -52,6 +52,7 @@
 #include <string>
 #include <vector>
 #include <algorithm>
+#include <map>
 
 /* libebml and matroska */
 #include "ebml/EbmlHead.h"
diff --git a/modules/demux/mkv/virtual_segment.cpp b/modules/demux/mkv/virtual_segment.cpp
index 42643f8..1b0b674 100644
--- a/modules/demux/mkv/virtual_segment.cpp
+++ b/modules/demux/mkv/virtual_segment.cpp
@@ -678,72 +678,71 @@ void virtual_chapter_c::print()
 
 void virtual_segment_c::KeepTrackSelection( matroska_segment_c & old, matroska_segment_c & next )
 {
-    size_t i, j;
+    typedef matroska_segment_c::tracks_map_t tracks_map_t;
+
     char *sub_lang = NULL, *aud_lang = NULL;
-    /* get the current ES language selection */
-    for( i = 0; i < old.tracks.size(); i++)
+    for( tracks_map_t::iterator it = old.tracks.begin(); it != old.tracks.end(); ++it )
     {
-        mkv_track_t *p_tk = old.tracks[i];
-        es_format_t *p_ofmt = &p_tk->fmt;
-        if( p_tk->p_es )
+        tracks_map_t::mapped_type& track = it->second;
+        if( track.p_es )
         {
             bool state = false;
-            es_out_Control( old.sys.demuxer.out, ES_OUT_GET_ES_STATE, p_tk->p_es, &state );
+            es_out_Control( old.sys.demuxer.out, ES_OUT_GET_ES_STATE, track.p_es, &state );
             if( state )
             {
-                if( p_ofmt->i_cat == AUDIO_ES )
-                    aud_lang = p_tk->fmt.psz_language;
-                else if( p_ofmt->i_cat == SPU_ES )
-                    sub_lang = p_tk->fmt.psz_language;
+                if( track.fmt.i_cat == AUDIO_ES )
+                    aud_lang = track.fmt.psz_language;
+                else if( track.fmt.i_cat == SPU_ES )
+                    sub_lang = track.fmt.psz_language;
             }
         }
     }
-    for( i = 0; i < next.tracks.size(); i++)
+    for( tracks_map_t::iterator it = next.tracks.begin(); it != next.tracks.end(); ++it )
     {
-        mkv_track_t *p_tk = next.tracks[i];
-        es_format_t *p_nfmt = &p_tk->fmt;
+        tracks_map_t::mapped_type& new_track = it->second;
+        es_format_t &              new_fmt   = new_track.fmt;
 
         /* Let's only do that for audio and video for now */
-        if( p_nfmt->i_cat == AUDIO_ES || p_nfmt->i_cat == VIDEO_ES )
+        if( new_fmt.i_cat == AUDIO_ES || new_fmt.i_cat == VIDEO_ES )
         {
-
             /* check for a similar elementary stream */
-            for( j = 0; j < old.tracks.size(); j++)
+            for( tracks_map_t::iterator old_it = old.tracks.begin(); old_it != old.tracks.end(); ++old_it )
             {
-                es_format_t * p_ofmt = &old.tracks[j]->fmt;
+                tracks_map_t::mapped_type& old_track = old_it->second;
+                es_format_t& old_fmt = old_track.fmt;
 
-                if( !old.tracks[j]->p_es )
+                if( !old_track.p_es )
                     continue;
 
-                if( ( p_nfmt->i_cat == p_ofmt->i_cat ) &&
-                    ( p_nfmt->i_codec == p_ofmt->i_codec ) &&
-                    ( p_nfmt->i_priority == p_ofmt->i_priority ) &&
-                    ( p_nfmt->i_bitrate == p_ofmt->i_bitrate ) &&
-                    ( p_nfmt->i_extra == p_ofmt->i_extra ) &&
-                    ( p_nfmt->i_extra == 0 ||
-                      !memcmp( p_nfmt->p_extra, p_ofmt->p_extra, p_nfmt->i_extra ) ) &&
-                    !strcasecmp( p_nfmt->psz_language, p_ofmt->psz_language ) &&
-                    ( ( p_nfmt->i_cat == AUDIO_ES &&
-                        !memcmp( &p_nfmt->audio, &p_ofmt->audio, sizeof(audio_format_t) ) ) ||
-                      ( p_nfmt->i_cat == VIDEO_ES &&
-                        !memcmp( &p_nfmt->video, &p_ofmt->video, sizeof(video_format_t) ) ) ) )
+                if( ( new_fmt.i_cat == old_fmt.i_cat ) &&
+                    ( new_fmt.i_codec == old_fmt.i_codec ) &&
+                    ( new_fmt.i_priority == old_fmt.i_priority ) &&
+                    ( new_fmt.i_bitrate == old_fmt.i_bitrate ) &&
+                    ( new_fmt.i_extra == old_fmt.i_extra ) &&
+                    ( new_fmt.i_extra == 0 ||
+                      !memcmp( new_fmt.p_extra, old_fmt.p_extra, new_fmt.i_extra ) ) &&
+                    !strcasecmp( new_fmt.psz_language, old_fmt.psz_language ) &&
+                    ( ( new_fmt.i_cat == AUDIO_ES &&
+                        !memcmp( &new_fmt.audio, &old_fmt.audio, sizeof(audio_format_t) ) ) ||
+                      ( new_fmt.i_cat == VIDEO_ES &&
+                        !memcmp( &new_fmt.video, &old_fmt.video, sizeof(video_format_t) ) ) ) )
                 {
                     /* FIXME handle video palettes... */
-                    msg_Warn( &old.sys.demuxer, "Reusing decoder of old track %zu for track %zu", j, i);
-                    p_tk->p_es = old.tracks[j]->p_es;
-                    old.tracks[j]->p_es = NULL;
+                    msg_Warn( &old.sys.demuxer, "Reusing decoder of old track %u for track %u", old_track.i_number, new_track.i_number);
+                    new_track.p_es = old_track.p_es;
+                    old_track.p_es = NULL;
                     break;
                 }
             }
         }
-        p_tk->fmt.i_priority &= ~(0x10);
-        if( ( sub_lang && p_nfmt->i_cat == SPU_ES && !strcasecmp(sub_lang, p_nfmt->psz_language) ) ||
-            ( aud_lang && p_nfmt->i_cat == AUDIO_ES && !strcasecmp(aud_lang, p_nfmt->psz_language) ) )
+        new_track.fmt.i_priority &= ~(0x10);
+        if( ( sub_lang && new_fmt.i_cat == SPU_ES && !strcasecmp(sub_lang, new_fmt.psz_language) ) ||
+            ( aud_lang && new_fmt.i_cat == AUDIO_ES && !strcasecmp(aud_lang, new_fmt.psz_language) ) )
         {
-            msg_Warn( &old.sys.demuxer, "Since previous segment used lang %s forcing track %zu",
-                      p_nfmt->psz_language, i);
-            p_tk->fmt.i_priority |= 0x10;
-            p_tk->b_forced = true;
+            msg_Warn( &old.sys.demuxer, "Since previous segment used lang %s forcing track %u",
+                      new_fmt.psz_language, new_track.i_number );
+            new_fmt.i_priority |= 0x10;
+            new_track.b_forced = true;
         }
     }
 }
-- 
2.8.2



More information about the vlc-devel mailing list