[vlc-devel] [PATCH] Fix Seek with Cues in Matroska
Denis Charmet
typx at dinauz.org
Wed Oct 19 23:51:01 CEST 2011
It is now more precise. Should fix #3019 #3026 (same bug) and avoid case where vlc infinitely loops at some ordered chapter change.
---
modules/demux/mkv/Ebml_parser.cpp | 5 ++
modules/demux/mkv/matroska_segment.cpp | 121 +++++++++++++++++++++++---------
2 files changed, 92 insertions(+), 34 deletions(-)
diff --git a/modules/demux/mkv/Ebml_parser.cpp b/modules/demux/mkv/Ebml_parser.cpp
index 505b424..69676bf 100644
--- a/modules/demux/mkv/Ebml_parser.cpp
+++ b/modules/demux/mkv/Ebml_parser.cpp
@@ -72,6 +72,11 @@ EbmlElement* EbmlParser::UnGet( uint64 i_block_pos, uint64 i_cluster_pos )
mi_user_level--;
}
}
+
+ /* Avoid data skip in BlockGet */
+ delete m_el[mi_level];
+ m_el[mi_level] = NULL;
+
m_got = NULL;
mb_keep = false;
if ( m_el[1] && m_el[1]->GetElementPosition() == i_cluster_pos )
diff --git a/modules/demux/mkv/matroska_segment.cpp b/modules/demux/mkv/matroska_segment.cpp
index fc8cd51..4a964d1 100644
--- a/modules/demux/mkv/matroska_segment.cpp
+++ b/modules/demux/mkv/matroska_segment.cpp
@@ -664,6 +664,17 @@ bool matroska_segment_c::LoadSeekHeadItem( const EbmlCallbacks & ClassInfos, int
return true;
}
+struct spoint
+{
+ spoint(unsigned int tk): i_track(tk),i_date(0), i_seek_pos(0), i_cluster_pos(0),
+ p_next(NULL){}
+ unsigned int i_track;
+ mtime_t i_date;
+ int64_t i_seek_pos;
+ int64_t i_cluster_pos;
+ spoint * p_next;
+};
+
void matroska_segment_c::Seek( mtime_t i_date, mtime_t i_time_offset, int64_t i_global_position )
{
KaxBlock *block;
@@ -673,6 +684,9 @@ void matroska_segment_c::Seek( mtime_t i_date, mtime_t i_time_offset, int64_t i_
size_t i_track;
int64_t i_seek_position = i_start_pos;
int64_t i_seek_time = i_start_time;
+ mtime_t i_pts = 0;
+ spoint *p_first = NULL;
+ spoint *p_last = NULL;
if( i_global_position >= 0 )
{
@@ -706,22 +720,28 @@ void matroska_segment_c::Seek( mtime_t i_date, mtime_t i_time_offset, int64_t i_
return;
}
+ /* Don't try complex seek if we seek to 0 */
+ if( i_date == 0 )
+ {
+ es_out_Control( sys.demuxer.out, ES_OUT_SET_NEXT_DISPLAY_TIME, 0 );
+ es.I_O().setFilePointer( i_start_pos );
+
+ delete ep;
+ ep = new EbmlParser( &es, segment, &sys.demuxer );
+ cluster = NULL;
+ 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;
@@ -738,19 +758,38 @@ void matroska_segment_c::Seek( mtime_t i_date, mtime_t i_time_offset, int64_t i_
sys.i_start_pts = i_date;
+ es_out_Control( sys.demuxer.out, ES_OUT_SET_NEXT_DISPLAY_TIME, 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++;
+ spoint * seekpoint = new spoint(i_track);
+ if( unlikely( !seekpoint ) )
+ {
+ for( spoint * sp = p_first; sp; )
+ {
+ spoint * tmp = sp;
+ sp = sp->p_next;
+ delete tmp;
+ }
+ return;
+ }
+ if( unlikely( !p_first ) )
+ {
+ p_first = seekpoint;
+ p_last = seekpoint;
+ }
+ else
+ {
+ p_last->p_next = seekpoint;
+ p_last = seekpoint;
+ }
}
}
- es_out_Control( sys.demuxer.out, ES_OUT_SET_NEXT_DISPLAY_TIME, i_date );
- while( i_track_skipping > 0 )
+ while( i_pts < i_date )
{
bool b_key_picture;
bool b_discardable_picture;
@@ -761,51 +800,65 @@ void matroska_segment_c::Seek( mtime_t i_date, mtime_t i_time_offset, int64_t i_
return;
}
+ /* check if block's track is in our list */
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;
+ i_pts = sys.i_chapter_time + simpleblock->GlobalTimecode() / (mtime_t) 1000;
else
- sys.i_pts = sys.i_chapter_time + block->GlobalTimecode() / (mtime_t) 1000;
+ i_pts = sys.i_chapter_time + block->GlobalTimecode() / (mtime_t) 1000;
if( i_track < tracks.size() )
{
- if( sys.i_pts > sys.i_start_pts )
+ if( tracks[i_track]->fmt.i_cat == VIDEO_ES && b_key_picture )
{
- 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( b_key_picture && 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, b_key_picture || b_discardable_picture );
- }
+ /* get the seekpoint */
+ spoint * sp;
+ for( sp = p_first; sp; sp = sp->p_next )
+ if( sp->i_track == i_track )
+ break;
+
+ sp->i_date = i_pts;
+ if( simpleblock )
+ sp->i_seek_pos = simpleblock->GetElementPosition();
+ else
+ sp->i_seek_pos = i_block_pos;
+ sp->i_cluster_pos = i_cluster_pos;
}
}
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 )
+ /* rewind to the last I img */
+ spoint * p_min;
+ for( p_min = p_first, p_last = p_first; p_last; p_last = p_last->p_next )
+ if( p_last->i_date < p_min->i_date )
+ p_min = p_last;
+
+ sys.i_pts = p_min->i_date;
+ cluster = (KaxCluster *) ep->UnGet( p_min->i_seek_pos, p_min->i_cluster_pos );
+
+ /* hack use BlockGet to get the cluster then goto the wanted block */
+ if ( !cluster )
{
- sys.i_start_pts = sys.i_pts;
+ bool b_key_picture;
+ bool b_discardable_picture;
+ BlockGet( block, simpleblock, &b_key_picture, &b_discardable_picture, &i_block_duration );
+ delete block;
+ cluster = (KaxCluster *) ep->UnGet( p_min->i_seek_pos, p_min->i_cluster_pos );
+ }
- es_out_Control( sys.demuxer.out, ES_OUT_SET_NEXT_DISPLAY_TIME, sys.i_start_pts );
+ while( p_first )
+ {
+ p_min = p_first;
+ p_first = p_first->p_next;
+ delete p_min;
}
}
--
1.7.5.4
More information about the vlc-devel
mailing list