Commit eb5b1167 authored by Denis Charmet's avatar Denis Charmet Committed by Jean-Baptiste Kempf

Matroska: Fix Seek with Cues

It is now more precise.
Should fix #3019 #3026 (same bug) and avoid case where vlc infinitely loops at some ordered chapter change.
Signed-off-by: default avatarJean-Baptiste Kempf <jb@videolan.org>
parent 167e86b9
...@@ -72,6 +72,11 @@ EbmlElement* EbmlParser::UnGet( uint64 i_block_pos, uint64 i_cluster_pos ) ...@@ -72,6 +72,11 @@ EbmlElement* EbmlParser::UnGet( uint64 i_block_pos, uint64 i_cluster_pos )
mi_user_level--; mi_user_level--;
} }
} }
/* Avoid data skip in BlockGet */
delete m_el[mi_level];
m_el[mi_level] = NULL;
m_got = NULL; m_got = NULL;
mb_keep = false; mb_keep = false;
if ( m_el[1] && m_el[1]->GetElementPosition() == i_cluster_pos ) if ( m_el[1] && m_el[1]->GetElementPosition() == i_cluster_pos )
......
...@@ -664,6 +664,17 @@ bool matroska_segment_c::LoadSeekHeadItem( const EbmlCallbacks & ClassInfos, int ...@@ -664,6 +664,17 @@ bool matroska_segment_c::LoadSeekHeadItem( const EbmlCallbacks & ClassInfos, int
return true; 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 ) void matroska_segment_c::Seek( mtime_t i_date, mtime_t i_time_offset, int64_t i_global_position )
{ {
KaxBlock *block; KaxBlock *block;
...@@ -673,6 +684,9 @@ void matroska_segment_c::Seek( mtime_t i_date, mtime_t i_time_offset, int64_t i_ ...@@ -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; size_t i_track;
int64_t i_seek_position = i_start_pos; int64_t i_seek_position = i_start_pos;
int64_t i_seek_time = i_start_time; 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 ) 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_ ...@@ -706,22 +720,28 @@ void matroska_segment_c::Seek( mtime_t i_date, mtime_t i_time_offset, int64_t i_
return; 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 ) if ( i_index > 0 )
{ {
int i_idx = 0; int i_idx = 0;
for( ; i_idx < i_index; i_idx++ ) for( ; i_idx < i_index; i_idx++ )
{
if( p_indexes[i_idx].i_time + i_time_offset > i_date ) if( p_indexes[i_idx].i_time + i_time_offset > i_date )
{
break; break;
}
}
if( i_idx > 0 ) if( i_idx > 0 )
{
i_idx--; i_idx--;
}
i_seek_position = p_indexes[i_idx].i_position; i_seek_position = p_indexes[i_idx].i_position;
i_seek_time = p_indexes[i_idx].i_time; 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_ ...@@ -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; 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 */ /* now parse until key frame */
i_track_skipping = 0; i_track_skipping = 0;
for( i_track = 0; i_track < tracks.size(); i_track++ ) for( i_track = 0; i_track < tracks.size(); i_track++ )
{ {
if( tracks[i_track]->fmt.i_cat == VIDEO_ES ) if( tracks[i_track]->fmt.i_cat == VIDEO_ES )
{ {
tracks[i_track]->b_search_keyframe = true; spoint * seekpoint = new spoint(i_track);
i_track_skipping++; 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_key_picture;
bool b_discardable_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_ ...@@ -761,51 +800,65 @@ void matroska_segment_c::Seek( mtime_t i_date, mtime_t i_time_offset, int64_t i_
return; return;
} }
/* check if block's track is in our list */
for( i_track = 0; i_track < tracks.size(); i_track++ ) for( i_track = 0; i_track < tracks.size(); i_track++ )
{ {
if( (simpleblock && tracks[i_track]->i_number == simpleblock->TrackNum()) || if( (simpleblock && tracks[i_track]->i_number == simpleblock->TrackNum()) ||
(block && tracks[i_track]->i_number == block->TrackNum()) ) (block && tracks[i_track]->i_number == block->TrackNum()) )
{
break; break;
}
} }
if( simpleblock ) 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 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( 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 )); /* get the seekpoint */
i_track_skipping = 0; spoint * sp;
} for( sp = p_first; sp; sp = sp->p_next )
else if( tracks[i_track]->fmt.i_cat == VIDEO_ES ) if( sp->i_track == i_track )
{ break;
if( b_key_picture && tracks[i_track]->b_search_keyframe )
{ sp->i_date = i_pts;
tracks[i_track]->b_search_keyframe = false; if( simpleblock )
i_track_skipping--; sp->i_seek_pos = simpleblock->GetElementPosition();
} else
if( !tracks[i_track]->b_search_keyframe ) sp->i_seek_pos = i_block_pos;
{ sp->i_cluster_pos = i_cluster_pos;
BlockDecode( &sys.demuxer, block, simpleblock, sys.i_pts, 0, b_key_picture || b_discardable_picture );
}
} }
} }
delete block; delete block;
} }
/* FIXME current ES_OUT_SET_NEXT_DISPLAY_TIME does not work that well if /* rewind to the last I img */
* the delay is too high. */ spoint * p_min;
if( sys.i_pts + 500*1000 < sys.i_start_pts ) 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;
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment