bool Preload( );
bool PreloadFamily( const matroska_segment_t & segment );
- size_t PreloadLinked( const demux_sys_t & of_sys, std::vector<matroska_segment_t*> & segments );
void ParseInfo( EbmlElement *info );
void ParseChapters( EbmlElement *chapters );
void ParseSeekHead( EbmlElement *seekhead );
static bool CompareSegmentUIDs( const matroska_segment_t * item_a, const matroska_segment_t * item_b );
};
+// class holding hard-linked segment together in the playback order
+class virtual_segment_t
+{
+public:
+ virtual_segment_t()
+ :i_current_segment(0)
+ {}
+
+ std::vector<matroska_segment_t*> linked_segments;
+ size_t i_current_segment;
+
+ void Sort();
+ size_t AddSegment( matroska_segment_t *p_segment );
+ void PreloadLinked( );
+ float Duration( ) const;
+ void LoadCues( );
+
+ matroska_segment_t * Segment() const
+ {
+ if ( linked_segments.size() == 0 || i_current_segment >= linked_segments.size() )
+ return NULL;
+ return linked_segments[i_current_segment];
+ }
+
+ bool SelectNext()
+ {
+ if ( i_current_segment < linked_segments.size()-1 )
+ {
+ i_current_segment++;
+ return true;
+ }
+ return false;
+ }
+};
+
class matroska_stream_t
{
public:
matroska_stream_t( demux_sys_t & demuxer )
:p_in(NULL)
,p_es(NULL)
- ,i_current_segment(-1)
,sys(demuxer)
- ,f_duration(-1.0)
{}
~matroska_stream_t()
EbmlStream *p_es;
std::vector<matroska_segment_t*> segments;
- size_t i_current_segment;
demux_sys_t & sys;
-
- /* duration of the stream */
- float f_duration;
-
- inline matroska_segment_t *Segment()
- {
- if ( i_current_segment >= 0 && size_t(i_current_segment) < segments.size() )
- return segments[i_current_segment];
- return NULL;
- }
-
- matroska_segment_t *FindSegment( const EbmlBinary & uid ) const;
void PreloadFamily( const matroska_segment_t & segment );
- size_t PreloadLinked( const demux_sys_t & of_sys );
- void PreparePlayback( );
};
class demux_sys_t
,i_chapter_time(0)
,meta(NULL)
,title(NULL)
- ,i_current_stream(-1)
+ ,p_current_segment(NULL)
+ ,f_duration(-1.0)
{}
~demux_sys_t()
input_title_t *title;
std::vector<matroska_stream_t*> streams;
- int i_current_stream;
std::vector<matroska_segment_t*> opened_segments;
+ virtual_segment_t *p_current_segment;
- inline matroska_stream_t *Stream()
- {
- if ( i_current_stream >= 0 && size_t(i_current_stream) < streams.size() )
- return streams[i_current_stream];
- return NULL;
- }
+ /* duration of the stream */
+ float f_duration;
matroska_segment_t *FindSegment( const EbmlBinary & uid ) const;
void PreloadFamily( );
- void PreloadLinked( );
+ void PreloadLinked( matroska_segment_t *p_segment );
void PreparePlayback( );
matroska_stream_t *AnalyseAllSegmentsFound( EbmlStream *p_estream );
};
goto error;
}
p_sys->streams.push_back( p_stream );
- p_sys->i_current_stream = 0;
p_stream->p_in = p_io_callback;
p_stream->p_es = p_io_stream;
{
p_stream->segments[i]->Preload();
}
- p_stream->i_current_segment = 0;
- p_segment = p_stream->Segment();
+ p_segment = p_stream->segments[0];
if( p_segment->cluster == NULL )
{
msg_Err( p_demux, "cannot find any cluster, damaged file ?" );
}
p_sys->PreloadFamily( );
- p_sys->PreloadLinked( );
+ p_sys->PreloadLinked( p_segment );
p_sys->PreparePlayback( );
if( !p_segment->b_cues || p_segment->i_index <= 0 )
static int Control( demux_t *p_demux, int i_query, va_list args )
{
demux_sys_t *p_sys = p_demux->p_sys;
- matroska_stream_t *p_stream = p_sys->Stream();
- if ( p_stream == NULL ) return VLC_EGENERIC;
- matroska_segment_t *p_segment = p_stream->Segment();
+ matroska_segment_t *p_segment = p_sys->p_current_segment->Segment();
int64_t *pi64;
double *pf, f;
int i_skp;
case DEMUX_GET_LENGTH:
pi64 = (int64_t*)va_arg( args, int64_t * );
- if( p_stream->f_duration > 0.0 )
+ if( p_sys->f_duration > 0.0 )
{
- *pi64 = (int64_t)(p_stream->f_duration * 1000);
+ *pi64 = (int64_t)(p_sys->f_duration * 1000);
return VLC_SUCCESS;
}
return VLC_EGENERIC;
case DEMUX_GET_POSITION:
pf = (double*)va_arg( args, double * );
- if ( p_stream->f_duration > 0.0 )
- *pf = (double)p_sys->i_pts / (1000.0 * p_stream->f_duration);
+ if ( p_sys->f_duration > 0.0 )
+ *pf = (double)p_sys->i_pts / (1000.0 * p_sys->f_duration);
return VLC_SUCCESS;
case DEMUX_SET_POSITION:
mtime_t i_duration )
{
demux_sys_t *p_sys = p_demux->p_sys;
- matroska_stream_t *p_stream = p_sys->Stream();
- matroska_segment_t *p_segment = p_stream->Segment();
+ matroska_segment_t *p_segment = p_sys->p_current_segment->Segment();
size_t i_track;
unsigned int i;
static void UpdateCurrentToChapter( demux_t & demux )
{
demux_sys_t & sys = *demux.p_sys;
- matroska_stream_t *p_stream = sys.Stream();
- matroska_segment_t *p_segment = p_stream->Segment();
+ matroska_segment_t *p_segment = sys.p_current_segment->Segment();
const chapter_item_t *psz_curr_chapter;
/* update current chapter/seekpoint */
static void Seek( demux_t *p_demux, mtime_t i_date, double f_percent, const chapter_item_t *psz_chapter)
{
demux_sys_t *p_sys = p_demux->p_sys;
- matroska_stream_t *p_stream = p_sys->Stream();
- matroska_segment_t *p_segment = p_stream->Segment();
+ matroska_segment_t *p_segment = p_sys->p_current_segment->Segment();
mtime_t i_time_offset = 0;
KaxBlock *block;
}
delete p_segment->ep;
- p_segment->ep = new EbmlParser( p_stream->p_es, p_segment->segment );
+ p_segment->ep = new EbmlParser( &p_segment->es, p_segment->segment );
p_segment->cluster = NULL;
/* seek without index or without date */
if( f_percent >= 0 && (config_GetInt( p_demux, "mkv-seek-percent" ) || !p_segment->b_cues || i_date < 0 ))
{
- if (p_stream->f_duration >= 0)
+ if (p_sys->f_duration >= 0)
{
- i_date = int64_t( f_percent * p_stream->f_duration * 1000.0 );
+ i_date = int64_t( f_percent * p_sys->f_duration * 1000.0 );
}
else
{
(int)( 100 * p_segment->index[i_index].i_position /
stream_Size( p_demux->s ) ) );
- p_stream->p_in->setFilePointer( p_segment->index[i_index].i_position,
+ p_segment->es.I_O().setFilePointer( p_segment->index[i_index].i_position,
seek_beginning );
p_sys->i_start_pts = i_date;
static int Demux( demux_t *p_demux)
{
demux_sys_t *p_sys = p_demux->p_sys;
- matroska_stream_t *p_stream = p_sys->Stream();
- matroska_segment_t *p_segment = p_stream->Segment();
+ matroska_segment_t *p_segment = p_sys->p_current_segment->Segment();
if ( p_segment == NULL ) return 0;
int i_block_count = 0;
if ( p_segment->editions.size() && p_segment->editions[p_segment->i_current_edition].b_ordered && p_segment->psz_current_chapter == NULL )
{
/* nothing left to read in this ordered edition */
- if ( p_stream->i_current_segment == p_stream->segments.size() - 1)
+ if ( !p_sys->p_current_segment->SelectNext() )
return 0;
p_segment->UnSelect( );
es_out_Control( p_demux->out, ES_OUT_RESET_PCR );
- /* switch to the next segment (TODO update the duration) */
- p_stream->i_current_segment++;
- p_segment = p_stream->Segment();
- if ( !p_segment || !p_segment->Select( 0 ) )
+ /* switch to the next segment */
+ p_segment = p_sys->p_current_segment->Segment();
+ if ( !p_segment->Select( 0 ) )
+ {
+ msg_Err( p_demux, "Failed to select new segment" );
return 0;
+ }
continue;
}
es_out_Control( p_demux->out, ES_OUT_RESET_PCR );
/* switch to the next segment */
- p_stream->i_current_segment++;
- p_segment = p_stream->Segment();
- if ( !p_segment || !p_segment->Select( 0 ) )
+ if ( !p_sys->p_current_segment->SelectNext() )
// no more segments in this stream
return 0;
+ p_segment = p_sys->p_current_segment->Segment();
+ if ( !p_segment->Select( 0 ) )
+ {
+ msg_Err( p_demux, "Failed to select new segment" );
+ return 0;
+ }
continue;
}
void demux_sys_t::PreloadFamily( )
{
+/* family handling disabled for the moment
matroska_stream_t *p_stream = Stream();
if ( p_stream )
{
}
}
}
+*/
}
void matroska_stream_t::PreloadFamily( const matroska_segment_t & of_segment )
}
// preload all the linked segments for all preloaded segments
-void demux_sys_t::PreloadLinked( )
+void demux_sys_t::PreloadLinked( matroska_segment_t *p_segment )
{
- size_t i_prealoaded;
- do {
- i_prealoaded = 0;
- for (size_t i=0; i<streams.size(); i++)
- {
- i_prealoaded += streams[i]->PreloadLinked( *this );
- }
- } while ( i_prealoaded ); // worst case: will stop when all segments are preloaded
-}
+ size_t i_preloaded, i;
-size_t matroska_stream_t::PreloadLinked( const demux_sys_t & of_sys )
-{
- size_t i_result = 0;
- for (size_t i=0; i<segments.size(); i++)
- {
- i_result += segments[i]->PreloadLinked( of_sys, segments );
- }
+ delete p_current_segment;
+ p_current_segment = new virtual_segment_t();
- return i_result;
-}
+ // fill our current virtual segment with the used segment from the current stream
+ p_current_segment->linked_segments.push_back( p_segment );
-size_t matroska_segment_t::PreloadLinked( const demux_sys_t & of_sys, std::vector<matroska_segment_t*> & segments )
-{
- size_t i_result = 0;
- if ( prev_segment_uid.GetBuffer() )
- {
- matroska_segment_t *p_segment = of_sys.FindSegment( prev_segment_uid );
- if ( p_segment )
- {
- if ( p_segment->Preload( ) )
- {
- segments.push_back( p_segment );
- i_result++;
- }
- }
- }
- if ( next_segment_uid.GetBuffer() )
- {
- matroska_segment_t *p_segment = of_sys.FindSegment( next_segment_uid );
- if ( p_segment )
+ // fill our current virtual segment with all hard linked segments
+ do {
+ i_preloaded = 0;
+ for ( i=0; i< opened_segments.size(); i++ )
{
- if ( p_segment->Preload( ) )
- {
- segments.push_back( p_segment );
- i_result++;
- }
+ i_preloaded += p_current_segment->AddSegment( opened_segments[i] );
}
- }
- return i_result;
-}
+ } while ( i_preloaded ); // worst case: will stop when all segments are found as linked
-void demux_sys_t::PreparePlayback( )
-{
- matroska_stream_t *p_stream = Stream();
- if ( p_stream )
- {
- p_stream->PreparePlayback( );
- }
+ p_current_segment->Sort( );
+
+ p_current_segment->PreloadLinked( );
}
-void matroska_stream_t::PreparePlayback( )
+void demux_sys_t::PreparePlayback( )
{
- size_t i;
-
- // update duration
- f_duration = 0.0;
- for (i=0; i<segments.size(); i++)
- {
- f_duration += segments[i]->f_duration;
-
- segments[i]->LoadCues( );
- }
-
- // sort segment order
- std::sort( segments.begin(), segments.end(), matroska_segment_t::CompareSegmentUIDs );
+ f_duration = p_current_segment->Duration();
+ p_current_segment->LoadCues();
}
bool matroska_segment_t::CompareSegmentUIDs( const matroska_segment_t * p_item_a, const matroska_segment_t * p_item_b )
matroska_segment_t *demux_sys_t::FindSegment( const EbmlBinary & uid ) const
{
- matroska_segment_t *p_segment = NULL;
- for (size_t i=0; i<streams.size() && p_segment == NULL; i++)
+ for (size_t i=0; i<opened_segments.size(); i++)
{
- p_segment = streams[i]->FindSegment( uid );
+ if ( opened_segments[i]->segment_uid == uid )
+ return opened_segments[i];
}
- return p_segment;
+ return NULL;
}
-matroska_segment_t *matroska_stream_t::FindSegment( const EbmlBinary & uid ) const
+void virtual_segment_t::Sort()
{
- for (size_t i=0; i<segments.size(); i++)
+ // keep the current segment index
+ matroska_segment_t *p_segment = linked_segments[i_current_segment];
+
+ std::sort( linked_segments.begin(), linked_segments.end(), matroska_segment_t::CompareSegmentUIDs );
+
+ for ( i_current_segment=0; i_current_segment<linked_segments.size(); i_current_segment++)
+ if ( linked_segments[i_current_segment] == p_segment )
+ break;
+}
+
+size_t virtual_segment_t::AddSegment( matroska_segment_t *p_segment )
+{
+ size_t i;
+ // check if it's not already in here
+ for ( i=0; i<linked_segments.size(); i++ )
{
- if ( segments[i]->segment_uid == uid )
- return segments[i];
+ if ( p_segment->segment_uid == linked_segments[i]->segment_uid )
+ return 0;
}
- return NULL;
+
+ // find possible mates
+ for ( i=0; i<linked_segments.size(); i++ )
+ {
+ if ( p_segment->segment_uid == linked_segments[i]->prev_segment_uid )
+ {
+ linked_segments.push_back( p_segment );
+ return 1;
+ }
+ if ( p_segment->segment_uid == linked_segments[i]->next_segment_uid )
+ {
+ linked_segments.push_back( p_segment );
+ return 1;
+ }
+ }
+ return 0;
}
+
+void virtual_segment_t::PreloadLinked( )
+{
+ for ( size_t i=0; i<linked_segments.size(); i++ )
+ {
+ linked_segments[i]->Preload( );
+ }
+}
+
+float virtual_segment_t::Duration() const
+{
+ float f_duration = 0.0;
+ for ( size_t i=0; i<linked_segments.size(); i++ )
+ {
+ f_duration += linked_segments[i]->f_duration;
+ }
+ return f_duration;
+}
+
+void virtual_segment_t::LoadCues( )
+{
+ for ( size_t i=0; i<linked_segments.size(); i++ )
+ {
+ linked_segments[i]->LoadCues();
+ }
+}
\ No newline at end of file