|
|
|
@ -790,188 +790,9 @@ bool matroska_segment_c::LoadSeekHeadItem( const EbmlCallbacks & ClassInfos, int |
|
|
|
return true; |
|
|
|
} |
|
|
|
|
|
|
|
struct spoint |
|
|
|
{ |
|
|
|
spoint(unsigned int tk, mtime_t mk_date, int64_t pos, int64_t cpos): |
|
|
|
i_track(tk),i_mk_date(mk_date), i_seek_pos(pos), |
|
|
|
i_cluster_pos(cpos){} |
|
|
|
unsigned int i_track; |
|
|
|
mtime_t i_mk_date; |
|
|
|
int64_t i_seek_pos; |
|
|
|
int64_t i_cluster_pos; |
|
|
|
}; |
|
|
|
|
|
|
|
void matroska_segment_c::Seek( mtime_t i_mk_date, mtime_t i_mk_time_offset ) |
|
|
|
{ |
|
|
|
KaxBlock *block; |
|
|
|
KaxSimpleBlock *simpleblock; |
|
|
|
int64_t i_block_duration; |
|
|
|
size_t i_track; |
|
|
|
int64_t i_seek_position = 0; // previously i_start_pos
|
|
|
|
mtime_t i_mk_seek_time = i_mk_start_time; |
|
|
|
mtime_t i_mk_pts = 0; |
|
|
|
int i_cat; |
|
|
|
bool b_has_key = false; |
|
|
|
|
|
|
|
for( size_t i = 0; i < tracks.size(); i++) |
|
|
|
tracks[i]->i_last_dts = VLC_TS_INVALID; |
|
|
|
|
|
|
|
/* Don't try complex seek if we seek to 0 */ |
|
|
|
if( i_mk_date == 0 && i_mk_time_offset == 0 ) |
|
|
|
{ |
|
|
|
es_out_Control( sys.demuxer.out, ES_OUT_SET_NEXT_DISPLAY_TIME, |
|
|
|
INT64_C(0) ); |
|
|
|
es.I_O().setFilePointer( 0 /* previously i_start_pos */ ); |
|
|
|
|
|
|
|
ep->reconstruct( &es, segment, &sys.demuxer ); |
|
|
|
|
|
|
|
cluster = NULL; |
|
|
|
sys.i_start_pts = VLC_TS_0; |
|
|
|
sys.i_pcr = sys.i_pts = VLC_TS_INVALID; |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
indexes_t::const_iterator index_it = indexes_begin(); |
|
|
|
|
|
|
|
if ( index_idx() ) |
|
|
|
{ |
|
|
|
index_it = std::upper_bound ( |
|
|
|
indexes_begin(), indexes_end(), i_mk_date, SeekIndexFinder( i_mk_time_offset ) |
|
|
|
); |
|
|
|
|
|
|
|
if (index_it != indexes_begin()) |
|
|
|
--index_it; |
|
|
|
|
|
|
|
i_seek_position = index_it->i_position; |
|
|
|
i_mk_seek_time = index_it->i_mk_time; |
|
|
|
} |
|
|
|
|
|
|
|
msg_Dbg( &sys.demuxer, "seek got %" PRId64 " - %" PRId64, i_mk_seek_time, i_seek_position ); |
|
|
|
|
|
|
|
es.I_O().setFilePointer( i_seek_position, seek_beginning ); |
|
|
|
|
|
|
|
ep->reconstruct( &es, segment, &sys.demuxer ); |
|
|
|
|
|
|
|
cluster = NULL; |
|
|
|
|
|
|
|
sys.i_start_pts = i_mk_date + VLC_TS_0; |
|
|
|
|
|
|
|
/* now parse until key frame */ |
|
|
|
std::vector<spoint> spoints; |
|
|
|
const int es_types[3] = { VIDEO_ES, AUDIO_ES, SPU_ES }; |
|
|
|
i_cat = es_types[0]; |
|
|
|
mtime_t i_seek_preroll = 0; |
|
|
|
for( int i = 0; i < 2; i_cat = es_types[++i] ) |
|
|
|
{ |
|
|
|
for( i_track = 0; i_track < tracks.size(); i_track++ ) |
|
|
|
{ |
|
|
|
if( tracks[i_track]->i_seek_preroll ) |
|
|
|
{ |
|
|
|
bool b_enabled; |
|
|
|
if( es_out_Control( sys.demuxer.out, |
|
|
|
ES_OUT_GET_ES_STATE, |
|
|
|
tracks[i_track]->p_es, |
|
|
|
&b_enabled ) == VLC_SUCCESS && |
|
|
|
b_enabled ) |
|
|
|
i_seek_preroll = __MAX( i_seek_preroll, |
|
|
|
tracks[i_track]->i_seek_preroll ); |
|
|
|
} |
|
|
|
if( tracks[i_track]->fmt.i_cat == i_cat ) |
|
|
|
{ |
|
|
|
spoints.push_back ( |
|
|
|
spoint (i_track, i_mk_seek_time, i_seek_position, i_seek_position) |
|
|
|
); |
|
|
|
} |
|
|
|
} |
|
|
|
if ( likely( !spoints.empty() ) ) |
|
|
|
break; |
|
|
|
} |
|
|
|
/*Neither video nor audio track... no seek further*/ |
|
|
|
if( unlikely( spoints.empty() ) ) |
|
|
|
{ |
|
|
|
es_out_Control( sys.demuxer.out, ES_OUT_SET_NEXT_DISPLAY_TIME, i_mk_date ); |
|
|
|
return; |
|
|
|
} |
|
|
|
i_mk_date -= i_seek_preroll; |
|
|
|
for(;;) |
|
|
|
{ |
|
|
|
do |
|
|
|
{ |
|
|
|
bool b_key_picture; |
|
|
|
bool b_discardable_picture; |
|
|
|
if( BlockGet( block, simpleblock, &b_key_picture, &b_discardable_picture, &i_block_duration ) ) |
|
|
|
{ |
|
|
|
msg_Warn( &sys.demuxer, "cannot get block EOF?" ); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
if( simpleblock ) |
|
|
|
i_mk_pts = sys.i_mk_chapter_time + simpleblock->GlobalTimecode() / INT64_C(1000); |
|
|
|
else |
|
|
|
i_mk_pts = sys.i_mk_chapter_time + block->GlobalTimecode() / INT64_C(1000); |
|
|
|
|
|
|
|
if( BlockFindTrackIndex( &i_track, block, simpleblock ) == VLC_SUCCESS ) |
|
|
|
{ |
|
|
|
if( tracks[i_track]->fmt.i_cat == i_cat && b_key_picture ) |
|
|
|
{ |
|
|
|
/* get the seekpoint */ |
|
|
|
std::vector<spoint>::iterator it; |
|
|
|
|
|
|
|
for ( it = spoints.begin (); it != spoints.end (); ++it ) |
|
|
|
if (it->i_track == i_track) |
|
|
|
break; |
|
|
|
|
|
|
|
if (unlikely (it == spoints.end ()) ) { |
|
|
|
msg_Err( &sys.demuxer, "Unable to locate seekpoint using i_track = %zu!", i_track); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
it->i_mk_date = i_mk_pts; |
|
|
|
if( simpleblock ) |
|
|
|
it->i_seek_pos = simpleblock->GetElementPosition(); |
|
|
|
else |
|
|
|
it->i_seek_pos = i_block_pos; |
|
|
|
it->i_cluster_pos = i_cluster_pos; |
|
|
|
b_has_key = true; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
delete block; |
|
|
|
} while( i_mk_pts < i_mk_date ); |
|
|
|
if( b_has_key || !index_idx()) |
|
|
|
break; |
|
|
|
|
|
|
|
/* No key picture was found in the cluster seek to previous seekpoint */ |
|
|
|
i_mk_date = i_mk_time_offset + index_it->i_mk_time; |
|
|
|
index_it--; |
|
|
|
i_mk_pts = 0; |
|
|
|
es.I_O().setFilePointer( index_it->i_position ); |
|
|
|
ep->reconstruct( &es, segment, &sys.demuxer ); |
|
|
|
cluster = NULL; |
|
|
|
} |
|
|
|
|
|
|
|
/* rewind to the last I img */ |
|
|
|
std::vector<spoint>::const_iterator it; |
|
|
|
std::vector<spoint>::const_iterator it_min = spoints.begin (); |
|
|
|
|
|
|
|
for (it = spoints.begin () + 1; it != spoints.end (); ++it) |
|
|
|
if ( it->i_mk_date < it_min->i_mk_date ) |
|
|
|
it_min = it; |
|
|
|
|
|
|
|
sys.i_pts = it_min->i_mk_date + VLC_TS_0; |
|
|
|
sys.i_pcr = VLC_TS_INVALID; |
|
|
|
es_out_Control( sys.demuxer.out, ES_OUT_SET_NEXT_DISPLAY_TIME, i_mk_date ); |
|
|
|
cluster = static_cast<KaxCluster*>( ep->UnGet( it_min->i_seek_pos, it_min->i_cluster_pos ) ); |
|
|
|
|
|
|
|
/* hack use BlockGet to get the cluster then goto the wanted block */ |
|
|
|
if ( !cluster ) |
|
|
|
{ |
|
|
|
bool b_key_picture; |
|
|
|
bool b_discardable_picture; |
|
|
|
BlockGet( block, simpleblock, &b_key_picture, &b_discardable_picture, &i_block_duration ); |
|
|
|
delete block; |
|
|
|
cluster = static_cast<KaxCluster*>( ep->UnGet( it_min->i_seek_pos, it_min->i_cluster_pos ) ); |
|
|
|
} |
|
|
|
// TODO: implement
|
|
|
|
} |
|
|
|
|
|
|
|
int matroska_segment_c::BlockFindTrackIndex( size_t *pi_track, |
|
|
|
|