Commit 4d60c14f authored by Derk-Jan Hartman's avatar Derk-Jan Hartman

mkv: Implement a dumb parser for files with broken or missing Seek Cue tables.

- This is REALLY slow.
- It is slow each time you Seek to somewhere that you have not been/played before.
- We ought to create a "Repair index" function instead, like for avi. (no time before release)

This close ticket #1687
parent fc3a1cf2
...@@ -1172,7 +1172,7 @@ public: ...@@ -1172,7 +1172,7 @@ public:
void LoadCues( KaxCues *cues ); void LoadCues( KaxCues *cues );
void LoadTags( KaxTags *tags ); void LoadTags( KaxTags *tags );
void InformationCreate( ); void InformationCreate( );
void Seek( mtime_t i_date, mtime_t i_time_offset ); void Seek( mtime_t i_date, mtime_t i_time_offset, int64_t i_global_position );
#if LIBMATROSKA_VERSION >= 0x000800 #if LIBMATROSKA_VERSION >= 0x000800
int BlockGet( KaxBlock * &, KaxSimpleBlock * &, int64_t *, int64_t *, int64_t *); int BlockGet( KaxBlock * &, KaxSimpleBlock * &, int64_t *, int64_t *, int64_t *);
#else #else
...@@ -1206,7 +1206,7 @@ public: ...@@ -1206,7 +1206,7 @@ public:
size_t AddSegment( matroska_segment_c *p_segment ); size_t AddSegment( matroska_segment_c *p_segment );
void PreloadLinked( ); void PreloadLinked( );
mtime_t Duration( ) const; mtime_t Duration( ) const;
void Seek( demux_t & demuxer, mtime_t i_date, mtime_t i_time_offset, chapter_item_c *psz_chapter ); void Seek( demux_t & demuxer, mtime_t i_date, mtime_t i_time_offset, chapter_item_c *psz_chapter, int64_t i_global_position );
inline chapter_edition_c *Edition() inline chapter_edition_c *Edition()
{ {
...@@ -3228,7 +3228,7 @@ bool virtual_segment_c::UpdateCurrentToChapter( demux_t & demux ) ...@@ -3228,7 +3228,7 @@ bool virtual_segment_c::UpdateCurrentToChapter( demux_t & demux )
{ {
// only physically seek if necessary // only physically seek if necessary
if ( psz_current_chapter == NULL || (psz_current_chapter->i_end_time != psz_curr_chapter->i_start_time) ) if ( psz_current_chapter == NULL || (psz_current_chapter->i_end_time != psz_curr_chapter->i_start_time) )
Seek( demux, sys.i_pts, 0, psz_curr_chapter ); Seek( demux, sys.i_pts, 0, psz_curr_chapter, -1 );
} }
} }
...@@ -3449,6 +3449,7 @@ static void Seek( demux_t *p_demux, mtime_t i_date, double f_percent, chapter_it ...@@ -3449,6 +3449,7 @@ static void Seek( demux_t *p_demux, mtime_t i_date, double f_percent, chapter_it
virtual_segment_c *p_vsegment = p_sys->p_current_segment; virtual_segment_c *p_vsegment = p_sys->p_current_segment;
matroska_segment_c *p_segment = p_vsegment->Segment(); matroska_segment_c *p_segment = p_vsegment->Segment();
mtime_t i_time_offset = 0; mtime_t i_time_offset = 0;
int64_t i_global_position = -1;
int i_index; int i_index;
...@@ -3475,13 +3476,13 @@ static void Seek( demux_t *p_demux, mtime_t i_date, double f_percent, chapter_it ...@@ -3475,13 +3476,13 @@ static void Seek( demux_t *p_demux, mtime_t i_date, double f_percent, chapter_it
{ {
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, "inacurate way of seeking" ); msg_Dbg( p_demux, "inaccurate 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->p_indexes[i_index].i_position >= i_pos) if( p_segment->b_cues && p_segment->p_indexes[i_index].i_position < i_pos )
{ break;
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 )
{ {
...@@ -3490,37 +3491,15 @@ static void Seek( demux_t *p_demux, mtime_t i_date, double f_percent, chapter_it ...@@ -3490,37 +3491,15 @@ static void Seek( demux_t *p_demux, mtime_t i_date, double f_percent, chapter_it
i_date = p_segment->p_indexes[i_index].i_time; i_date = p_segment->p_indexes[i_index].i_time;
#if 0 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 ))
if( p_segment->p_indexes[i_index].i_position < i_pos )
{ {
EbmlElement *el; msg_Dbg( p_demux, "no cues, seek request to global pos: %"PRId64, i_pos );
i_global_position = i_pos;
msg_Warn( p_demux, "searching for cluster, could take some time" );
/* search a cluster */
while( ( el = p_sys->ep->Get() ) != NULL )
{
if( MKV_IS_ID( el, KaxCluster ) )
{
KaxCluster *cluster = (KaxCluster*)el;
/* add it to the index */
p_segment->IndexAppendCluster( cluster );
if( (int64_t)cluster->GetElementPosition() >= i_pos )
{
p_sys->cluster = cluster;
p_sys->ep->Down();
break;
}
}
}
} }
#endif
} }
} }
p_vsegment->Seek( *p_demux, i_date, i_time_offset, psz_chapter ); p_vsegment->Seek( *p_demux, i_date, i_time_offset, psz_chapter, i_global_position );
} }
/***************************************************************************** /*****************************************************************************
...@@ -5542,7 +5521,7 @@ void demux_sys_t::JumpTo( virtual_segment_c & vsegment, chapter_item_c * p_chapt ...@@ -5542,7 +5521,7 @@ void demux_sys_t::JumpTo( virtual_segment_c & vsegment, chapter_item_c * p_chapt
if ( !p_chapter->Enter( true ) ) if ( !p_chapter->Enter( true ) )
{ {
// jump to the location in the found segment // jump to the location in the found segment
vsegment.Seek( demuxer, p_chapter->i_user_start_time, -1, p_chapter ); vsegment.Seek( demuxer, p_chapter->i_user_start_time, -1, p_chapter, -1 );
} }
} }
...@@ -5879,7 +5858,7 @@ void virtual_segment_c::AppendUID( const EbmlBinary * p_UID ) ...@@ -5879,7 +5858,7 @@ void virtual_segment_c::AppendUID( const EbmlBinary * p_UID )
linked_uids.push_back( *(KaxSegmentUID*)(p_UID) ); linked_uids.push_back( *(KaxSegmentUID*)(p_UID) );
} }
void matroska_segment_c::Seek( mtime_t i_date, mtime_t i_time_offset ) void matroska_segment_c::Seek( mtime_t i_date, mtime_t i_time_offset, int64_t i_global_position )
{ {
KaxBlock *block; KaxBlock *block;
#if LIBMATROSKA_VERSION >= 0x000800 #if LIBMATROSKA_VERSION >= 0x000800
...@@ -5893,6 +5872,39 @@ void matroska_segment_c::Seek( mtime_t i_date, mtime_t i_time_offset ) ...@@ -5893,6 +5872,39 @@ void matroska_segment_c::Seek( mtime_t i_date, mtime_t i_time_offset )
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;
if( i_global_position >= 0 )
{
/* Special case for seeking in files with no cues */
EbmlElement *el = NULL;
es.I_O().setFilePointer( i_start_pos, seek_beginning );
delete ep;
ep = new EbmlParser( &es, segment, &sys.demuxer );
cluster = NULL;
while( ( el = ep->Get() ) != NULL )
{
if( MKV_IS_ID( el, KaxCluster ) )
{
cluster = (KaxCluster *)el;
i_cluster_pos = cluster->GetElementPosition();
if( i_index == 0 ||
( i_index > 0 && p_indexes[i_index - 1].i_position < (int64_t)cluster->GetElementPosition() ) )
{
IndexAppendCluster( cluster );
}
if( es.I_O().getFilePointer() >= i_global_position )
{
ParseCluster();
msg_Dbg( &sys.demuxer, "we found a cluster that is in the neighbourhood" );
es_out_Control( sys.demuxer.out, ES_OUT_RESET_PCR );
return;
}
}
}
msg_Err( &sys.demuxer, "This file has no cues, and we were unable to seek to the requested position by parsing." );
return;
}
if ( i_index > 0 ) if ( i_index > 0 )
{ {
int i_idx = 0; int i_idx = 0;
...@@ -5939,7 +5951,6 @@ void matroska_segment_c::Seek( mtime_t i_date, mtime_t i_time_offset ) ...@@ -5939,7 +5951,6 @@ void matroska_segment_c::Seek( mtime_t i_date, mtime_t i_time_offset )
es_out_Control( sys.demuxer.out, ES_OUT_SET_NEXT_DISPLAY_TIME, tracks[i_track]->p_es, i_date ); es_out_Control( sys.demuxer.out, ES_OUT_SET_NEXT_DISPLAY_TIME, tracks[i_track]->p_es, i_date );
} }
while( i_track_skipping > 0 ) while( i_track_skipping > 0 )
{ {
#if LIBMATROSKA_VERSION >= 0x000800 #if LIBMATROSKA_VERSION >= 0x000800
...@@ -6015,7 +6026,7 @@ void matroska_segment_c::Seek( mtime_t i_date, mtime_t i_time_offset ) ...@@ -6015,7 +6026,7 @@ void matroska_segment_c::Seek( mtime_t i_date, mtime_t i_time_offset )
} }
} }
void virtual_segment_c::Seek( demux_t & demuxer, mtime_t i_date, mtime_t i_time_offset, chapter_item_c *psz_chapter ) void virtual_segment_c::Seek( demux_t & demuxer, mtime_t i_date, mtime_t i_time_offset, chapter_item_c *psz_chapter, int64_t i_global_position )
{ {
demux_sys_t *p_sys = demuxer.p_sys; demux_sys_t *p_sys = demuxer.p_sys;
size_t i; size_t i;
...@@ -6059,7 +6070,7 @@ void virtual_segment_c::Seek( demux_t & demuxer, mtime_t i_date, mtime_t i_time_ ...@@ -6059,7 +6070,7 @@ void virtual_segment_c::Seek( demux_t & demuxer, mtime_t i_date, mtime_t i_time_
i_current_segment = i; i_current_segment = i;
} }
linked_segments[i]->Seek( i_date, i_time_offset ); linked_segments[i]->Seek( i_date, i_time_offset, i_global_position );
} }
void chapter_codec_cmds_c::AddCommand( const KaxChapterProcessCommand & command ) void chapter_codec_cmds_c::AddCommand( const KaxChapterProcessCommand & command )
...@@ -6604,7 +6615,7 @@ bool dvd_command_interpretor_c::Interpret( const binary * p_command, size_t i_si ...@@ -6604,7 +6615,7 @@ bool dvd_command_interpretor_c::Interpret( const binary * p_command, size_t i_si
{ {
if ( !p_chapter->Enter( true ) ) if ( !p_chapter->Enter( true ) )
// jump to the location in the found segment // jump to the location in the found segment
sys.p_current_segment->Seek( sys.demuxer, p_chapter->i_user_start_time, -1, p_chapter ); sys.p_current_segment->Seek( sys.demuxer, p_chapter->i_user_start_time, -1, p_chapter, -1 );
f_result = true; f_result = true;
} }
...@@ -6622,7 +6633,7 @@ bool dvd_command_interpretor_c::Interpret( const binary * p_command, size_t i_si ...@@ -6622,7 +6633,7 @@ bool dvd_command_interpretor_c::Interpret( const binary * p_command, size_t i_si
{ {
if ( !p_chapter->Enter( true ) ) if ( !p_chapter->Enter( true ) )
// jump to the location in the found segment // jump to the location in the found segment
sys.p_current_segment->Seek( sys.demuxer, p_chapter->i_user_start_time, -1, p_chapter ); sys.p_current_segment->Seek( sys.demuxer, p_chapter->i_user_start_time, -1, p_chapter, -1 );
f_result = true; f_result = true;
} }
...@@ -6854,7 +6865,7 @@ bool matroska_script_interpretor_c::Interpret( const binary * p_command, size_t ...@@ -6854,7 +6865,7 @@ bool matroska_script_interpretor_c::Interpret( const binary * p_command, size_t
else else
{ {
if ( !p_chapter->EnterAndLeave( sys.p_current_segment->CurrentChapter() ) ) if ( !p_chapter->EnterAndLeave( sys.p_current_segment->CurrentChapter() ) )
p_segment->Seek( sys.demuxer, p_chapter->i_user_start_time, -1, p_chapter ); p_segment->Seek( sys.demuxer, p_chapter->i_user_start_time, -1, p_chapter, -1 );
b_result = true; b_result = true;
} }
} }
......
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