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

MKV: Fix seeking without cues

the demux generates its own cues while reading and when seeking.
This should also avoid crashes when seeking without cues.

Closes #5085 and #5712
Signed-off-by: default avatarJean-Baptiste Kempf <jb@videolan.org>
parent 811ce44f
...@@ -427,7 +427,7 @@ void matroska_segment_c::IndexAppendCluster( KaxCluster *cluster ) ...@@ -427,7 +427,7 @@ void matroska_segment_c::IndexAppendCluster( KaxCluster *cluster )
idx.i_track = -1; idx.i_track = -1;
idx.i_block_number= -1; idx.i_block_number= -1;
idx.i_position = cluster->GetElementPosition(); idx.i_position = cluster->GetElementPosition();
idx.i_time = -1; idx.i_time = cluster->GlobalTimecode()/ (mtime_t) 1000;
idx.b_key = true; idx.b_key = true;
i_index++; i_index++;
...@@ -668,8 +668,9 @@ bool matroska_segment_c::LoadSeekHeadItem( const EbmlCallbacks & ClassInfos, int ...@@ -668,8 +668,9 @@ bool matroska_segment_c::LoadSeekHeadItem( const EbmlCallbacks & ClassInfos, int
struct spoint struct spoint
{ {
spoint(unsigned int tk): i_track(tk),i_date(0), i_seek_pos(0), i_cluster_pos(0), spoint(unsigned int tk, mtime_t date, int64_t pos, int64_t cpos):
p_next(NULL){} i_track(tk),i_date(date), i_seek_pos(pos),
i_cluster_pos(cpos), p_next(NULL){}
unsigned int i_track; unsigned int i_track;
mtime_t i_date; mtime_t i_date;
int64_t i_seek_pos; int64_t i_seek_pos;
...@@ -693,7 +694,13 @@ void matroska_segment_c::Seek( mtime_t i_date, mtime_t i_time_offset, int64_t i_ ...@@ -693,7 +694,13 @@ void matroska_segment_c::Seek( mtime_t i_date, mtime_t i_time_offset, int64_t i_
{ {
/* Special case for seeking in files with no cues */ /* Special case for seeking in files with no cues */
EbmlElement *el = NULL; EbmlElement *el = NULL;
/* Start from the last known index instead of the beginning eachtime */
if( i_index == 0)
es.I_O().setFilePointer( i_start_pos, seek_beginning ); es.I_O().setFilePointer( i_start_pos, seek_beginning );
else
es.I_O().setFilePointer( p_indexes[ i_index - 1 ].i_position,
seek_beginning );
delete ep; delete ep;
ep = new EbmlParser( &es, segment, &sys.demuxer ); ep = new EbmlParser( &es, segment, &sys.demuxer );
cluster = NULL; cluster = NULL;
...@@ -705,21 +712,17 @@ void matroska_segment_c::Seek( mtime_t i_date, mtime_t i_time_offset, int64_t i_ ...@@ -705,21 +712,17 @@ void matroska_segment_c::Seek( mtime_t i_date, mtime_t i_time_offset, int64_t i_
cluster = (KaxCluster *)el; cluster = (KaxCluster *)el;
i_cluster_pos = cluster->GetElementPosition(); i_cluster_pos = cluster->GetElementPosition();
if( i_index == 0 || if( i_index == 0 ||
( i_index > 0 && p_indexes[i_index - 1].i_position < (int64_t)cluster->GetElementPosition() ) ) ( i_index > 0 &&
p_indexes[i_index - 1].i_position < (int64_t)cluster->GetElementPosition() ) )
{ {
ParseCluster();
IndexAppendCluster( cluster ); IndexAppendCluster( cluster );
} }
if( es.I_O().getFilePointer() >= (unsigned) i_global_position ) if( es.I_O().getFilePointer() >= (unsigned) i_global_position )
{ break;
ParseCluster();
msg_Dbg( &sys.demuxer, "we found a cluster that is in the neighbourhood" );
return;
} }
} }
} }
msg_Err( &sys.demuxer, "This file has no cues, and we were unable to seek to the requested position by parsing." );
return;
}
/* Don't try complex seek if we seek to 0 */ /* Don't try complex seek if we seek to 0 */
if( i_date == 0 ) if( i_date == 0 )
...@@ -766,7 +769,7 @@ void matroska_segment_c::Seek( mtime_t i_date, mtime_t i_time_offset, int64_t i_ ...@@ -766,7 +769,7 @@ void matroska_segment_c::Seek( mtime_t i_date, mtime_t i_time_offset, int64_t i_
{ {
if( tracks[i_track]->fmt.i_cat == VIDEO_ES ) if( tracks[i_track]->fmt.i_cat == VIDEO_ES )
{ {
spoint * seekpoint = new spoint(i_track); spoint * seekpoint = new spoint(i_track, i_seek_time, i_seek_position, i_seek_position);
if( unlikely( !seekpoint ) ) if( unlikely( !seekpoint ) )
{ {
for( spoint * sp = p_first; sp; ) for( spoint * sp = p_first; sp; )
...@@ -813,7 +816,6 @@ void matroska_segment_c::Seek( mtime_t i_date, mtime_t i_time_offset, int64_t i_ ...@@ -813,7 +816,6 @@ void matroska_segment_c::Seek( mtime_t i_date, mtime_t i_time_offset, int64_t i_
i_pts = sys.i_chapter_time + simpleblock->GlobalTimecode() / (mtime_t) 1000; i_pts = sys.i_chapter_time + simpleblock->GlobalTimecode() / (mtime_t) 1000;
else else
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( tracks[i_track]->fmt.i_cat == VIDEO_ES && b_key_picture ) if( tracks[i_track]->fmt.i_cat == VIDEO_ES && b_key_picture )
...@@ -1436,13 +1438,6 @@ int matroska_segment_c::BlockGet( KaxBlock * & pp_block, KaxSimpleBlock * & pp_s ...@@ -1436,13 +1438,6 @@ int matroska_segment_c::BlockGet( KaxBlock * & pp_block, KaxSimpleBlock * & pp_s
cluster = (KaxCluster*)el; cluster = (KaxCluster*)el;
i_cluster_pos = cluster->GetElementPosition(); i_cluster_pos = cluster->GetElementPosition();
/* add it to the index */
if( i_index == 0 ||
( i_index > 0 && p_indexes[i_index - 1].i_position < (int64_t)cluster->GetElementPosition() ) )
{
IndexAppendCluster( cluster );
}
// reset silent tracks // reset silent tracks
for (size_t i=0; i<tracks.size(); i++) for (size_t i=0; i<tracks.size(); i++)
{ {
...@@ -1468,6 +1463,12 @@ int matroska_segment_c::BlockGet( KaxBlock * & pp_block, KaxSimpleBlock * & pp_s ...@@ -1468,6 +1463,12 @@ int matroska_segment_c::BlockGet( KaxBlock * & pp_block, KaxSimpleBlock * & pp_s
ctc.ReadData( es.I_O(), SCOPE_ALL_DATA ); ctc.ReadData( es.I_O(), SCOPE_ALL_DATA );
cluster->InitTimecode( uint64( ctc ), i_timescale ); cluster->InitTimecode( uint64( ctc ), i_timescale );
/* add it to the index */
if( i_index == 0 ||
( i_index > 0 &&
p_indexes[i_index - 1].i_position < (int64_t)cluster->GetElementPosition() ) )
IndexAppendCluster( cluster );
} }
else if( MKV_IS_ID( el, KaxClusterSilentTracks ) ) else if( MKV_IS_ID( el, KaxClusterSilentTracks ) )
{ {
......
...@@ -410,49 +410,45 @@ static void Seek( demux_t *p_demux, mtime_t i_date, double f_percent, virtual_ch ...@@ -410,49 +410,45 @@ static void Seek( demux_t *p_demux, mtime_t i_date, double f_percent, virtual_ch
msg_Dbg( p_demux, "seek request to %"PRId64" (%f%%)", i_date, f_percent ); msg_Dbg( p_demux, "seek request to %"PRId64" (%f%%)", i_date, f_percent );
if( i_date < 0 && f_percent < 0 ) if( i_date < 0 && f_percent < 0 )
{ {
msg_Warn( p_demux, "cannot seek nowhere !" ); msg_Warn( p_demux, "cannot seek nowhere!" );
return; return;
} }
if( f_percent > 1.0 ) if( f_percent > 1.0 )
{ {
msg_Warn( p_demux, "cannot seek so far !" ); msg_Warn( p_demux, "cannot seek so far!" );
return;
}
if( p_sys->f_duration < 0 )
{
msg_Warn( p_demux, "cannot seek without duration!");
return; return;
} }
/* seek without index or without date */ /* seek without index or without date */
if( f_percent >= 0 && (var_InheritBool( p_demux, "mkv-seek-percent" ) || !p_segment->b_cues || i_date < 0 )) if( f_percent >= 0 && (var_InheritBool( p_demux, "mkv-seek-percent" ) || !p_segment->b_cues || i_date < 0 ))
{
if( p_sys->f_duration >= 0 && p_segment->b_cues )
{ {
i_date = int64_t( f_percent * p_sys->f_duration * 1000.0 ); i_date = int64_t( f_percent * p_sys->f_duration * 1000.0 );
} if( !p_segment->b_cues )
else
{ {
int64_t i_pos = int64_t( f_percent * stream_Size( p_demux->s ) ); int64_t i_pos = int64_t( f_percent * stream_Size( p_demux->s ) );
msg_Dbg( p_demux, "inaccurate way of seeking for pos:%"PRId64, i_pos ); msg_Dbg( p_demux, "lengthy way of seeking for pos:%"PRId64, i_pos );
for( i_index = 0; i_index < p_segment->i_index; i_index++ ) for( i_index = 0; i_index < p_segment->i_index; i_index++ )
{ {
if( p_segment->b_cues && p_segment->p_indexes[i_index].i_position < i_pos ) if( p_segment->p_indexes[i_index].i_position >= i_pos &&
break; p_segment->p_indexes[i_index].i_time > 0 )
if( !p_segment->b_cues && p_segment->p_indexes[i_index].i_position >= i_pos && p_segment->p_indexes[i_index].i_time > 0 )
break; break;
} }
if( i_index == p_segment->i_index ) if( i_index == p_segment->i_index )
{
i_index--; i_index--;
}
i_date = p_segment->p_indexes[i_index].i_time; if( p_segment->p_indexes[i_index].i_position < i_pos )
if( !p_segment->b_cues && ( p_segment->p_indexes[i_index].i_position < i_pos || p_segment->p_indexes[i_index].i_position - i_pos > 2000000 ))
{ {
msg_Dbg( p_demux, "no cues, seek request to global pos: %"PRId64, i_pos ); msg_Dbg( p_demux, "no cues, seek request to global pos: %"PRId64, i_pos );
i_global_position = i_pos; i_global_position = i_pos;
} }
} }
} }
p_vsegment->Seek( *p_demux, i_date, i_time_offset, p_chapter, i_global_position ); p_vsegment->Seek( *p_demux, i_date, i_time_offset, p_chapter, i_global_position );
} }
......
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