+ delete block;
+ continue;
+ }
+
+#if LIBMATROSKA_VERSION >= 0x000800
+ BlockDecode( p_demux, block, simpleblock, p_sys->i_pts, i_block_duration, i_block_ref1 >= 0 || i_block_ref2 > 0 );
+#else
+ BlockDecode( p_demux, block, p_sys->i_pts, i_block_duration, i_block_ref1 >= 0 || i_block_ref2 > 0 );
+#endif
+
+ delete block;
+ i_block_count++;
+
+ // TODO optimize when there is need to leave or when seeking has been called
+ if( i_block_count > 5 )
+ {
+ i_return = 1;
+ break;
+ }
+ }
+
+ vlc_mutex_unlock( &p_sys->lock_demuxer );
+
+ return i_return;
+}
+
+
+
+/*****************************************************************************
+ * Stream managment
+ *****************************************************************************/
+vlc_stream_io_callback::vlc_stream_io_callback( stream_t *s_, vlc_bool_t b_owner_ )
+{
+ s = s_;
+ b_owner = b_owner_;
+ mb_eof = VLC_FALSE;
+}
+
+uint32 vlc_stream_io_callback::read( void *p_buffer, size_t i_size )
+{
+ if( i_size <= 0 || mb_eof )
+ {
+ return 0;
+ }
+
+ return stream_Read( s, p_buffer, i_size );
+}
+void vlc_stream_io_callback::setFilePointer(int64_t i_offset, seek_mode mode )
+{
+ int64_t i_pos;
+
+ switch( mode )
+ {
+ case seek_beginning:
+ i_pos = i_offset;
+ break;
+ case seek_end:
+ i_pos = stream_Size( s ) - i_offset;
+ break;
+ default:
+ i_pos= stream_Tell( s ) + i_offset;
+ break;
+ }
+
+ if( i_pos < 0 || i_pos >= stream_Size( s ) )
+ {
+ mb_eof = VLC_TRUE;
+ return;
+ }
+
+ mb_eof = VLC_FALSE;
+ if( stream_Seek( s, i_pos ) )
+ {
+ mb_eof = VLC_TRUE;
+ }
+ return;
+}
+size_t vlc_stream_io_callback::write( const void *p_buffer, size_t i_size )
+{
+ return 0;
+}
+uint64 vlc_stream_io_callback::getFilePointer( void )
+{
+ if ( s == NULL )
+ return 0;
+ return stream_Tell( s );
+}
+void vlc_stream_io_callback::close( void )
+{
+ return;
+}
+
+
+/*****************************************************************************
+ * Ebml Stream parser
+ *****************************************************************************/
+EbmlParser::EbmlParser( EbmlStream *es, EbmlElement *el_start, demux_t *p_demux )
+{
+ int i;
+
+ m_es = es;
+ m_got = NULL;
+ m_el[0] = el_start;
+ mi_remain_size[0] = el_start->GetSize();
+
+ for( i = 1; i < 6; i++ )
+ {
+ m_el[i] = NULL;
+ }
+ mi_level = 1;
+ mi_user_level = 1;
+ mb_keep = VLC_FALSE;
+ mb_dummy = config_GetInt( p_demux, "mkv-use-dummy" );
+}
+
+EbmlParser::~EbmlParser( void )
+{
+ int i;
+
+ for( i = 1; i < mi_level; i++ )
+ {
+ if( !mb_keep )
+ {
+ delete m_el[i];
+ }
+ mb_keep = VLC_FALSE;
+ }
+}
+
+EbmlElement* EbmlParser::UnGet( uint64 i_block_pos, uint64 i_cluster_pos )
+{
+ if ( mi_user_level > mi_level )
+ {
+ while ( mi_user_level != mi_level )
+ {
+ delete m_el[mi_user_level];
+ m_el[mi_user_level] = NULL;
+ mi_user_level--;
+ }
+ }
+ m_got = NULL;
+ mb_keep = VLC_FALSE;
+ if ( m_el[1]->GetElementPosition() == i_cluster_pos )
+ {
+ m_es->I_O().setFilePointer( i_block_pos, seek_beginning );
+ return (EbmlMaster*) m_el[1];
+ }
+ else
+ {
+ // seek to the previous Cluster
+ m_es->I_O().setFilePointer( i_cluster_pos, seek_beginning );
+ mi_level--;
+ mi_user_level--;
+ delete m_el[mi_level];
+ m_el[mi_level] = NULL;
+ return NULL;
+ }
+}
+
+void EbmlParser::Up( void )
+{
+ if( mi_user_level == mi_level )
+ {
+ fprintf( stderr," arrrrrrrrrrrrrg Up cannot escape itself\n" );
+ }
+
+ mi_user_level--;
+}
+
+void EbmlParser::Down( void )
+{
+ mi_user_level++;
+ mi_level++;
+}
+
+void EbmlParser::Keep( void )
+{
+ mb_keep = VLC_TRUE;
+}
+
+int EbmlParser::GetLevel( void )
+{
+ return mi_user_level;
+}
+
+void EbmlParser::Reset( demux_t *p_demux )
+{
+ while ( mi_level > 0)
+ {
+ delete m_el[mi_level];
+ m_el[mi_level] = NULL;
+ mi_level--;
+ }
+ mi_user_level = mi_level = 1;
+#if LIBEBML_VERSION >= 0x000704
+ // a little faster and cleaner
+ m_es->I_O().setFilePointer( static_cast<KaxSegment*>(m_el[0])->GetGlobalPosition(0) );
+#else
+ m_es->I_O().setFilePointer( m_el[0]->GetElementPosition() + m_el[0]->ElementSize(true) - m_el[0]->GetSize() );
+#endif
+ mb_dummy = config_GetInt( p_demux, "mkv-use-dummy" );
+}
+
+EbmlElement *EbmlParser::Get( void )
+{
+ int i_ulev = 0;
+
+ if( mi_user_level != mi_level )
+ {
+ return NULL;
+ }
+ if( m_got )
+ {
+ EbmlElement *ret = m_got;
+ m_got = NULL;
+
+ return ret;
+ }
+
+ if( m_el[mi_level] )
+ {
+ m_el[mi_level]->SkipData( *m_es, m_el[mi_level]->Generic().Context );
+ if( !mb_keep )
+ {
+ delete m_el[mi_level];
+ }
+ mb_keep = VLC_FALSE;
+ }
+
+ m_el[mi_level] = m_es->FindNextElement( m_el[mi_level - 1]->Generic().Context, i_ulev, 0xFFFFFFFFL, mb_dummy != 0, 1 );
+// mi_remain_size[mi_level] = m_el[mi_level]->GetSize();
+ if( i_ulev > 0 )
+ {
+ while( i_ulev > 0 )
+ {
+ if( mi_level == 1 )
+ {
+ mi_level = 0;
+ return NULL;
+ }
+
+ delete m_el[mi_level - 1];
+ m_got = m_el[mi_level -1] = m_el[mi_level];
+ m_el[mi_level] = NULL;
+
+ mi_level--;
+ i_ulev--;
+ }
+ return NULL;
+ }
+ else if( m_el[mi_level] == NULL )
+ {
+ fprintf( stderr," m_el[mi_level] == NULL\n" );
+ }
+
+ return m_el[mi_level];
+}
+
+
+/*****************************************************************************
+ * Tools
+ * * LoadCues : load the cues element and update index
+ *
+ * * LoadTags : load ... the tags element
+ *
+ * * InformationCreate : create all information, load tags if present
+ *
+ *****************************************************************************/
+void matroska_segment_c::LoadCues( )
+{
+ int64_t i_sav_position = es.I_O().getFilePointer();
+ EbmlParser *ep;
+ EbmlElement *el, *cues;
+
+ /* *** Load the cue if found *** */
+ if( i_cues_position < 0 )
+ {
+ msg_Warn( &sys.demuxer, "no cues/empty cues found->seek won't be precise" );
+
+// IndexAppendCluster( cluster );
+ }
+
+ vlc_bool_t b_seekable;
+
+ stream_Control( sys.demuxer.s, STREAM_CAN_FASTSEEK, &b_seekable );
+ if( !b_seekable )
+ return;
+
+ msg_Dbg( &sys.demuxer, "loading cues" );
+ es.I_O().setFilePointer( i_cues_position, seek_beginning );
+ cues = es.FindNextID( KaxCues::ClassInfos, 0xFFFFFFFFL);
+
+ if( cues == NULL )
+ {
+ msg_Err( &sys.demuxer, "cannot load cues (broken seekhead or file)" );
+ es.I_O().setFilePointer( i_sav_position, seek_beginning );
+ return;
+ }
+
+ ep = new EbmlParser( &es, cues, &sys.demuxer );
+ while( ( el = ep->Get() ) != NULL )
+ {
+ if( MKV_IS_ID( el, KaxCuePoint ) )
+ {
+#define idx p_indexes[i_index]
+
+ idx.i_track = -1;
+ idx.i_block_number= -1;
+ idx.i_position = -1;
+ idx.i_time = 0;
+ idx.b_key = VLC_TRUE;
+
+ ep->Down();
+ while( ( el = ep->Get() ) != NULL )
+ {
+ if( MKV_IS_ID( el, KaxCueTime ) )
+ {
+ KaxCueTime &ctime = *(KaxCueTime*)el;
+
+ ctime.ReadData( es.I_O() );
+
+ idx.i_time = uint64( ctime ) * i_timescale / (mtime_t)1000;
+ }
+ else if( MKV_IS_ID( el, KaxCueTrackPositions ) )
+ {
+ ep->Down();
+ while( ( el = ep->Get() ) != NULL )
+ {
+ if( MKV_IS_ID( el, KaxCueTrack ) )
+ {
+ KaxCueTrack &ctrack = *(KaxCueTrack*)el;
+
+ ctrack.ReadData( es.I_O() );
+ idx.i_track = uint16( ctrack );
+ }
+ else if( MKV_IS_ID( el, KaxCueClusterPosition ) )
+ {
+ KaxCueClusterPosition &ccpos = *(KaxCueClusterPosition*)el;
+
+ ccpos.ReadData( es.I_O() );
+ idx.i_position = segment->GetGlobalPosition( uint64( ccpos ) );
+ }
+ else if( MKV_IS_ID( el, KaxCueBlockNumber ) )
+ {
+ KaxCueBlockNumber &cbnum = *(KaxCueBlockNumber*)el;
+
+ cbnum.ReadData( es.I_O() );
+ idx.i_block_number = uint32( cbnum );
+ }
+ else
+ {
+ msg_Dbg( &sys.demuxer, " * Unknown (%s)", typeid(*el).name() );
+ }
+ }
+ ep->Up();
+ }
+ else
+ {
+ msg_Dbg( &sys.demuxer, " * Unknown (%s)", typeid(*el).name() );
+ }
+ }
+ ep->Up();
+
+#if 0
+ msg_Dbg( &sys.demuxer, " * added time="I64Fd" pos="I64Fd
+ " track=%d bnum=%d", idx.i_time, idx.i_position,
+ idx.i_track, idx.i_block_number );
+#endif
+
+ i_index++;
+ if( i_index >= i_index_max )
+ {
+ i_index_max += 1024;
+ p_indexes = (mkv_index_t*)realloc( p_indexes, sizeof( mkv_index_t ) * i_index_max );
+ }
+#undef idx
+ }
+ else
+ {
+ msg_Dbg( &sys.demuxer, " * Unknown (%s)", typeid(*el).name() );
+ }
+ }
+ delete ep;
+ delete cues;
+
+ b_cues = VLC_TRUE;
+
+ msg_Dbg( &sys.demuxer, "loading cues done." );
+ es.I_O().setFilePointer( i_sav_position, seek_beginning );
+}
+
+void matroska_segment_c::LoadTags( )
+{
+ int64_t i_sav_position = es.I_O().getFilePointer();
+ EbmlParser *ep;
+ EbmlElement *el, *tags;
+
+ msg_Dbg( &sys.demuxer, "loading tags" );
+ es.I_O().setFilePointer( i_tags_position, seek_beginning );
+ tags = es.FindNextID( KaxTags::ClassInfos, 0xFFFFFFFFL);
+
+ if( tags == NULL )
+ {
+ msg_Err( &sys.demuxer, "cannot load tags (broken seekhead or file)" );
+ es.I_O().setFilePointer( i_sav_position, seek_beginning );
+ return;
+ }
+
+ msg_Dbg( &sys.demuxer, "Tags" );
+ ep = new EbmlParser( &es, tags, &sys.demuxer );
+ while( ( el = ep->Get() ) != NULL )
+ {
+ if( MKV_IS_ID( el, KaxTag ) )
+ {
+ msg_Dbg( &sys.demuxer, "+ Tag" );
+ ep->Down();
+ while( ( el = ep->Get() ) != NULL )
+ {
+ if( MKV_IS_ID( el, KaxTagTargets ) )
+ {
+ msg_Dbg( &sys.demuxer, "| + Targets" );
+ ep->Down();
+ while( ( el = ep->Get() ) != NULL )
+ {
+ msg_Dbg( &sys.demuxer, "| | + Unknown (%s)", typeid( *el ).name() );
+ }
+ ep->Up();
+ }
+ else if( MKV_IS_ID( el, KaxTagGeneral ) )
+ {
+ msg_Dbg( &sys.demuxer, "| + General" );
+ ep->Down();
+ while( ( el = ep->Get() ) != NULL )
+ {
+ msg_Dbg( &sys.demuxer, "| | + Unknown (%s)", typeid( *el ).name() );
+ }
+ ep->Up();
+ }
+ else if( MKV_IS_ID( el, KaxTagGenres ) )
+ {
+ msg_Dbg( &sys.demuxer, "| + Genres" );
+ ep->Down();
+ while( ( el = ep->Get() ) != NULL )
+ {
+ msg_Dbg( &sys.demuxer, "| | + Unknown (%s)", typeid( *el ).name() );
+ }
+ ep->Up();
+ }
+ else if( MKV_IS_ID( el, KaxTagAudioSpecific ) )
+ {
+ msg_Dbg( &sys.demuxer, "| + Audio Specific" );
+ ep->Down();
+ while( ( el = ep->Get() ) != NULL )
+ {
+ msg_Dbg( &sys.demuxer, "| | + Unknown (%s)", typeid( *el ).name() );
+ }
+ ep->Up();
+ }
+ else if( MKV_IS_ID( el, KaxTagImageSpecific ) )
+ {
+ msg_Dbg( &sys.demuxer, "| + Images Specific" );
+ ep->Down();
+ while( ( el = ep->Get() ) != NULL )
+ {
+ msg_Dbg( &sys.demuxer, "| | + Unknown (%s)", typeid( *el ).name() );
+ }
+ ep->Up();
+ }
+ else if( MKV_IS_ID( el, KaxTagMultiComment ) )
+ {
+ msg_Dbg( &sys.demuxer, "| + Multi Comment" );
+ }
+ else if( MKV_IS_ID( el, KaxTagMultiCommercial ) )
+ {
+ msg_Dbg( &sys.demuxer, "| + Multi Commercial" );
+ }
+ else if( MKV_IS_ID( el, KaxTagMultiDate ) )
+ {
+ msg_Dbg( &sys.demuxer, "| + Multi Date" );
+ }
+ else if( MKV_IS_ID( el, KaxTagMultiEntity ) )
+ {
+ msg_Dbg( &sys.demuxer, "| + Multi Entity" );
+ }
+ else if( MKV_IS_ID( el, KaxTagMultiIdentifier ) )
+ {
+ msg_Dbg( &sys.demuxer, "| + Multi Identifier" );
+ }
+ else if( MKV_IS_ID( el, KaxTagMultiLegal ) )
+ {
+ msg_Dbg( &sys.demuxer, "| + Multi Legal" );
+ }
+ else if( MKV_IS_ID( el, KaxTagMultiTitle ) )
+ {
+ msg_Dbg( &sys.demuxer, "| + Multi Title" );
+ }
+ else
+ {
+ msg_Dbg( &sys.demuxer, "| + Unknown (%s)", typeid( *el ).name() );
+ }
+ }
+ ep->Up();
+ }
+ else
+ {
+ msg_Dbg( &sys.demuxer, "+ Unknown (%s)", typeid( *el ).name() );
+ }
+ }
+ delete ep;
+ delete tags;
+
+ msg_Dbg( &sys.demuxer, "loading tags done." );
+ es.I_O().setFilePointer( i_sav_position, seek_beginning );
+}
+
+/*****************************************************************************
+ * ParseSeekHead:
+ *****************************************************************************/
+void matroska_segment_c::ParseSeekHead( KaxSeekHead *seekhead )
+{
+ EbmlElement *el;
+ size_t i, j;
+ int i_upper_level = 0;
+
+ msg_Dbg( &sys.demuxer, "| + Seek head" );
+
+ /* Master elements */
+ seekhead->Read( es, seekhead->Generic().Context, i_upper_level, el, true );
+
+ for( i = 0; i < seekhead->ListSize(); i++ )
+ {
+ EbmlElement *l = (*seekhead)[i];
+
+ if( MKV_IS_ID( l, KaxSeek ) )
+ {
+ EbmlMaster *sk = static_cast<EbmlMaster *>(l);
+ EbmlId id = EbmlVoid::ClassInfos.GlobalId;
+ int64_t i_pos = -1;
+
+ for( j = 0; j < sk->ListSize(); j++ )
+ {
+ EbmlElement *l = (*sk)[j];
+
+ if( MKV_IS_ID( l, KaxSeekID ) )
+ {
+ KaxSeekID &sid = *(KaxSeekID*)l;
+ id = EbmlId( sid.GetBuffer(), sid.GetSize() );
+ }
+ else if( MKV_IS_ID( l, KaxSeekPosition ) )
+ {
+ KaxSeekPosition &spos = *(KaxSeekPosition*)l;
+ i_pos = uint64( spos );
+ }
+ else
+ {
+ msg_Dbg( &sys.demuxer, "| | | + Unknown (%s)", typeid(*l).name() );
+ }
+ }
+
+ if( i_pos >= 0 )
+ {
+ if( id == KaxCues::ClassInfos.GlobalId )
+ {
+ msg_Dbg( &sys.demuxer, "| | | = cues at "I64Fd, i_pos );
+ i_cues_position = segment->GetGlobalPosition( i_pos );
+ }
+ else if( id == KaxChapters::ClassInfos.GlobalId )
+ {
+ msg_Dbg( &sys.demuxer, "| | | = chapters at "I64Fd, i_pos );
+ i_chapters_position = segment->GetGlobalPosition( i_pos );
+ }
+ else if( id == KaxTags::ClassInfos.GlobalId )
+ {
+ msg_Dbg( &sys.demuxer, "| | | = tags at "I64Fd, i_pos );
+ i_tags_position = segment->GetGlobalPosition( i_pos );
+ }
+ }
+ }
+ else
+ {
+ msg_Dbg( &sys.demuxer, "| | + Unknown (%s)", typeid(*l).name() );
+ }
+ }
+}
+
+/*****************************************************************************
+ * ParseTrackEntry:
+ *****************************************************************************/
+void matroska_segment_c::ParseTrackEntry( KaxTrackEntry *m )
+{
+ size_t i, j, k, n;
+ bool bSupported = true;
+
+ mkv_track_t *tk;
+
+ msg_Dbg( &sys.demuxer, "| | + Track Entry" );
+
+ tk = new mkv_track_t();
+
+ /* Init the track */
+ memset( tk, 0, sizeof( mkv_track_t ) );
+
+ es_format_Init( &tk->fmt, UNKNOWN_ES, 0 );
+ tk->fmt.psz_language = strdup("English");
+ tk->fmt.psz_description = NULL;
+
+ tk->b_default = VLC_TRUE;
+ tk->b_enabled = VLC_TRUE;
+ tk->b_silent = VLC_FALSE;
+ tk->i_number = tracks.size() - 1;
+ tk->i_extra_data = 0;
+ tk->p_extra_data = NULL;
+ tk->psz_codec = NULL;
+ tk->i_default_duration = 0;
+ tk->f_timecodescale = 1.0;
+
+ tk->b_inited = VLC_FALSE;
+ tk->i_data_init = 0;
+ tk->p_data_init = NULL;
+
+ tk->psz_codec_name = NULL;
+ tk->psz_codec_settings = NULL;
+ tk->psz_codec_info_url = NULL;
+ tk->psz_codec_download_url = NULL;
+
+ tk->i_compression_type = MATROSKA_COMPRESSION_NONE;
+ tk->p_compression_data = NULL;
+
+ for( i = 0; i < m->ListSize(); i++ )
+ {
+ EbmlElement *l = (*m)[i];
+
+ if( MKV_IS_ID( l, KaxTrackNumber ) )
+ {
+ KaxTrackNumber &tnum = *(KaxTrackNumber*)l;
+
+ tk->i_number = uint32( tnum );
+ msg_Dbg( &sys.demuxer, "| | | + Track Number=%u", uint32( tnum ) );
+ }
+ else if( MKV_IS_ID( l, KaxTrackUID ) )
+ {
+ KaxTrackUID &tuid = *(KaxTrackUID*)l;
+
+ msg_Dbg( &sys.demuxer, "| | | + Track UID=%u", uint32( tuid ) );
+ }
+ else if( MKV_IS_ID( l, KaxTrackType ) )
+ {
+ const char *psz_type;
+ KaxTrackType &ttype = *(KaxTrackType*)l;
+
+ switch( uint8(ttype) )
+ {
+ case track_audio:
+ psz_type = "audio";
+ tk->fmt.i_cat = AUDIO_ES;
+ break;
+ case track_video:
+ psz_type = "video";
+ tk->fmt.i_cat = VIDEO_ES;
+ break;
+ case track_subtitle:
+ psz_type = "subtitle";
+ tk->fmt.i_cat = SPU_ES;
+ break;
+ case track_buttons:
+ psz_type = "buttons";
+ tk->fmt.i_cat = SPU_ES;
+ break;
+ default:
+ psz_type = "unknown";
+ tk->fmt.i_cat = UNKNOWN_ES;
+ break;
+ }
+
+ msg_Dbg( &sys.demuxer, "| | | + Track Type=%s", psz_type );
+ }
+// else if( EbmlId( *l ) == KaxTrackFlagEnabled::ClassInfos.GlobalId )
+// {
+// KaxTrackFlagEnabled &fenb = *(KaxTrackFlagEnabled*)l;
+
+// tk->b_enabled = uint32( fenb );
+// msg_Dbg( &sys.demuxer, "| | | + Track Enabled=%u",
+// uint32( fenb ) );
+// }
+ else if( MKV_IS_ID( l, KaxTrackFlagDefault ) )
+ {
+ KaxTrackFlagDefault &fdef = *(KaxTrackFlagDefault*)l;
+
+ tk->b_default = uint32( fdef );
+ msg_Dbg( &sys.demuxer, "| | | + Track Default=%u", uint32( fdef ) );
+ }
+ else if( MKV_IS_ID( l, KaxTrackFlagLacing ) )
+ {
+ KaxTrackFlagLacing &lac = *(KaxTrackFlagLacing*)l;
+
+ msg_Dbg( &sys.demuxer, "| | | + Track Lacing=%d", uint32( lac ) );
+ }
+ else if( MKV_IS_ID( l, KaxTrackMinCache ) )
+ {
+ KaxTrackMinCache &cmin = *(KaxTrackMinCache*)l;
+
+ msg_Dbg( &sys.demuxer, "| | | + Track MinCache=%d", uint32( cmin ) );
+ }
+ else if( MKV_IS_ID( l, KaxTrackMaxCache ) )
+ {
+ KaxTrackMaxCache &cmax = *(KaxTrackMaxCache*)l;
+
+ msg_Dbg( &sys.demuxer, "| | | + Track MaxCache=%d", uint32( cmax ) );
+ }
+ else if( MKV_IS_ID( l, KaxTrackDefaultDuration ) )
+ {
+ KaxTrackDefaultDuration &defd = *(KaxTrackDefaultDuration*)l;
+
+ tk->i_default_duration = uint64(defd);
+ msg_Dbg( &sys.demuxer, "| | | + Track Default Duration="I64Fd, uint64(defd) );
+ }
+ else if( MKV_IS_ID( l, KaxTrackTimecodeScale ) )
+ {
+ KaxTrackTimecodeScale &ttcs = *(KaxTrackTimecodeScale*)l;
+
+ tk->f_timecodescale = float( ttcs );
+ msg_Dbg( &sys.demuxer, "| | | + Track TimeCodeScale=%f", tk->f_timecodescale );
+ }
+ else if( MKV_IS_ID( l, KaxTrackName ) )
+ {
+ KaxTrackName &tname = *(KaxTrackName*)l;
+
+ tk->fmt.psz_description = ToUTF8( UTFstring( tname ) );
+ msg_Dbg( &sys.demuxer, "| | | + Track Name=%s", tk->fmt.psz_description );
+ }
+ else if( MKV_IS_ID( l, KaxTrackLanguage ) )
+ {
+ KaxTrackLanguage &lang = *(KaxTrackLanguage*)l;
+
+ if ( tk->fmt.psz_language != NULL )
+ free( tk->fmt.psz_language );
+ tk->fmt.psz_language = strdup( string( lang ).c_str() );
+ msg_Dbg( &sys.demuxer,
+ "| | | + Track Language=`%s'", tk->fmt.psz_language );
+ }
+ else if( MKV_IS_ID( l, KaxCodecID ) )
+ {
+ KaxCodecID &codecid = *(KaxCodecID*)l;
+
+ tk->psz_codec = strdup( string( codecid ).c_str() );
+ msg_Dbg( &sys.demuxer, "| | | + Track CodecId=%s", string( codecid ).c_str() );
+ }
+ else if( MKV_IS_ID( l, KaxCodecPrivate ) )
+ {
+ KaxCodecPrivate &cpriv = *(KaxCodecPrivate*)l;
+
+ tk->i_extra_data = cpriv.GetSize();
+ if( tk->i_extra_data > 0 )
+ {
+ tk->p_extra_data = (uint8_t*)malloc( tk->i_extra_data );
+ memcpy( tk->p_extra_data, cpriv.GetBuffer(), tk->i_extra_data );
+ }
+ msg_Dbg( &sys.demuxer, "| | | + Track CodecPrivate size="I64Fd, cpriv.GetSize() );
+ }
+ else if( MKV_IS_ID( l, KaxCodecName ) )
+ {
+ KaxCodecName &cname = *(KaxCodecName*)l;
+
+ tk->psz_codec_name = ToUTF8( UTFstring( cname ) );
+ msg_Dbg( &sys.demuxer, "| | | + Track Codec Name=%s", tk->psz_codec_name );
+ }
+ else if( MKV_IS_ID( l, KaxContentEncodings ) )
+ {
+ EbmlMaster *cencs = static_cast<EbmlMaster*>(l);
+ MkvTree( sys.demuxer, 3, "Content Encodings" );
+ if ( cencs->ListSize() > 1 )
+ {
+ msg_Err( &sys.demuxer, "Multiple Compression method not supported" );
+ bSupported = false;
+ }
+ for( j = 0; j < cencs->ListSize(); j++ )
+ {
+ EbmlElement *l2 = (*cencs)[j];
+ if( MKV_IS_ID( l2, KaxContentEncoding ) )
+ {
+ MkvTree( sys.demuxer, 4, "Content Encoding" );
+ EbmlMaster *cenc = static_cast<EbmlMaster*>(l2);
+ for( k = 0; k < cenc->ListSize(); k++ )
+ {
+ EbmlElement *l3 = (*cenc)[k];
+ if( MKV_IS_ID( l3, KaxContentEncodingOrder ) )
+ {
+ KaxContentEncodingOrder &encord = *(KaxContentEncodingOrder*)l3;
+ MkvTree( sys.demuxer, 5, "Order: %i", uint32( encord ) );
+ }
+ else if( MKV_IS_ID( l3, KaxContentEncodingScope ) )
+ {
+ KaxContentEncodingScope &encscope = *(KaxContentEncodingScope*)l3;
+ MkvTree( sys.demuxer, 5, "Scope: %i", uint32( encscope ) );
+ }
+ else if( MKV_IS_ID( l3, KaxContentEncodingType ) )
+ {
+ KaxContentEncodingType &enctype = *(KaxContentEncodingType*)l3;
+ MkvTree( sys.demuxer, 5, "Type: %i", uint32( enctype ) );
+ }
+ else if( MKV_IS_ID( l3, KaxContentCompression ) )
+ {
+ EbmlMaster *compr = static_cast<EbmlMaster*>(l3);
+ MkvTree( sys.demuxer, 5, "Content Compression" );
+ for( n = 0; n < compr->ListSize(); n++ )
+ {
+ EbmlElement *l4 = (*compr)[n];
+ if( MKV_IS_ID( l4, KaxContentCompAlgo ) )
+ {
+ KaxContentCompAlgo &compalg = *(KaxContentCompAlgo*)l4;
+ MkvTree( sys.demuxer, 6, "Compression Algorithm: %i", uint32(compalg) );
+ tk->i_compression_type = uint32( compalg );
+ if ( ( tk->i_compression_type != MATROSKA_COMPRESSION_ZLIB ) &&
+ ( tk->i_compression_type != MATROSKA_COMPRESSION_HEADER ) )
+ {
+ msg_Err( &sys.demuxer, "Track Compression method %d not supported", tk->i_compression_type );
+ bSupported = false;
+ }
+ }
+ else if( MKV_IS_ID( l4, KaxContentCompSettings ) )
+ {
+ tk->p_compression_data = new KaxContentCompSettings( *(KaxContentCompSettings*)l4 );
+ }
+ else
+ {
+ MkvTree( sys.demuxer, 6, "Unknown (%s)", typeid(*l4).name() );
+ }
+ }
+ }
+ else
+ {
+ MkvTree( sys.demuxer, 5, "Unknown (%s)", typeid(*l3).name() );
+ }
+ }
+ }
+ else
+ {
+ MkvTree( sys.demuxer, 4, "Unknown (%s)", typeid(*l2).name() );
+ }
+ }
+ }
+// else if( EbmlId( *l ) == KaxCodecSettings::ClassInfos.GlobalId )
+// {
+// KaxCodecSettings &cset = *(KaxCodecSettings*)l;
+
+// tk->psz_codec_settings = ToUTF8( UTFstring( cset ) );
+// msg_Dbg( &sys.demuxer, "| | | + Track Codec Settings=%s", tk->psz_codec_settings );
+// }
+// else if( EbmlId( *l ) == KaxCodecInfoURL::ClassInfos.GlobalId )
+// {
+// KaxCodecInfoURL &ciurl = *(KaxCodecInfoURL*)l;
+
+// tk->psz_codec_info_url = strdup( string( ciurl ).c_str() );
+// msg_Dbg( &sys.demuxer, "| | | + Track Codec Info URL=%s", tk->psz_codec_info_url );
+// }
+// else if( EbmlId( *l ) == KaxCodecDownloadURL::ClassInfos.GlobalId )
+// {
+// KaxCodecDownloadURL &cdurl = *(KaxCodecDownloadURL*)l;
+
+// tk->psz_codec_download_url = strdup( string( cdurl ).c_str() );
+// msg_Dbg( &sys.demuxer, "| | | + Track Codec Info URL=%s", tk->psz_codec_download_url );
+// }
+// else if( EbmlId( *l ) == KaxCodecDecodeAll::ClassInfos.GlobalId )
+// {
+// KaxCodecDecodeAll &cdall = *(KaxCodecDecodeAll*)l;
+
+// msg_Dbg( &sys.demuxer, "| | | + Track Codec Decode All=%u <== UNUSED", uint8( cdall ) );
+// }
+// else if( EbmlId( *l ) == KaxTrackOverlay::ClassInfos.GlobalId )
+// {
+// KaxTrackOverlay &tovr = *(KaxTrackOverlay*)l;
+
+// msg_Dbg( &sys.demuxer, "| | | + Track Overlay=%u <== UNUSED", uint32( tovr ) );
+// }
+ else if( MKV_IS_ID( l, KaxTrackVideo ) )
+ {
+ EbmlMaster *tkv = static_cast<EbmlMaster*>(l);
+ unsigned int j;
+ unsigned int i_crop_right = 0, i_crop_left = 0, i_crop_top = 0, i_crop_bottom = 0;
+ unsigned int i_display_unit = 0, i_display_width = 0, i_display_height = 0;
+
+ msg_Dbg( &sys.demuxer, "| | | + Track Video" );
+ tk->f_fps = 0.0;
+
+ tk->fmt.video.i_frame_rate_base = (unsigned int)(tk->i_default_duration / 1000);
+ tk->fmt.video.i_frame_rate = 1000000;
+
+ for( j = 0; j < tkv->ListSize(); j++ )
+ {
+ EbmlElement *l = (*tkv)[j];
+// if( EbmlId( *el4 ) == KaxVideoFlagInterlaced::ClassInfos.GlobalId )
+// {
+// KaxVideoFlagInterlaced &fint = *(KaxVideoFlagInterlaced*)el4;
+
+// msg_Dbg( &sys.demuxer, "| | | | + Track Video Interlaced=%u", uint8( fint ) );
+// }
+// else if( EbmlId( *el4 ) == KaxVideoStereoMode::ClassInfos.GlobalId )
+// {
+// KaxVideoStereoMode &stereo = *(KaxVideoStereoMode*)el4;
+
+// msg_Dbg( &sys.demuxer, "| | | | + Track Video Stereo Mode=%u", uint8( stereo ) );
+// }
+// else
+ if( MKV_IS_ID( l, KaxVideoPixelWidth ) )
+ {
+ KaxVideoPixelWidth &vwidth = *(KaxVideoPixelWidth*)l;
+
+ tk->fmt.video.i_width += uint16( vwidth );
+ msg_Dbg( &sys.demuxer, "| | | | + width=%d", uint16( vwidth ) );
+ }
+ else if( MKV_IS_ID( l, KaxVideoPixelHeight ) )
+ {
+ KaxVideoPixelWidth &vheight = *(KaxVideoPixelWidth*)l;
+
+ tk->fmt.video.i_height += uint16( vheight );
+ msg_Dbg( &sys.demuxer, "| | | | + height=%d", uint16( vheight ) );
+ }
+ else if( MKV_IS_ID( l, KaxVideoDisplayWidth ) )
+ {
+ KaxVideoDisplayWidth &vwidth = *(KaxVideoDisplayWidth*)l;
+
+ i_display_width = uint16( vwidth );
+ msg_Dbg( &sys.demuxer, "| | | | + display width=%d", uint16( vwidth ) );
+ }
+ else if( MKV_IS_ID( l, KaxVideoDisplayHeight ) )
+ {
+ KaxVideoDisplayWidth &vheight = *(KaxVideoDisplayWidth*)l;
+
+ i_display_height = uint16( vheight );
+ msg_Dbg( &sys.demuxer, "| | | | + display height=%d", uint16( vheight ) );
+ }
+ else if( MKV_IS_ID( l, KaxVideoPixelCropBottom ) )
+ {
+ KaxVideoPixelCropBottom &cropval = *(KaxVideoPixelCropBottom*)l;
+
+ i_crop_bottom = uint16( cropval );
+ msg_Dbg( &sys.demuxer, "| | | | + crop pixel bottom=%d", uint16( cropval ) );
+ }
+ else if( MKV_IS_ID( l, KaxVideoPixelCropTop ) )
+ {
+ KaxVideoPixelCropTop &cropval = *(KaxVideoPixelCropTop*)l;
+
+ i_crop_top = uint16( cropval );
+ msg_Dbg( &sys.demuxer, "| | | | + crop pixel top=%d", uint16( cropval ) );
+ }
+ else if( MKV_IS_ID( l, KaxVideoPixelCropRight ) )
+ {
+ KaxVideoPixelCropRight &cropval = *(KaxVideoPixelCropRight*)l;
+
+ i_crop_right = uint16( cropval );
+ msg_Dbg( &sys.demuxer, "| | | | + crop pixel right=%d", uint16( cropval ) );
+ }
+ else if( MKV_IS_ID( l, KaxVideoPixelCropLeft ) )
+ {
+ KaxVideoPixelCropLeft &cropval = *(KaxVideoPixelCropLeft*)l;
+
+ i_crop_left = uint16( cropval );
+ msg_Dbg( &sys.demuxer, "| | | | + crop pixel left=%d", uint16( cropval ) );
+ }
+ else if( MKV_IS_ID( l, KaxVideoFrameRate ) )
+ {
+ KaxVideoFrameRate &vfps = *(KaxVideoFrameRate*)l;
+
+ tk->f_fps = float( vfps );
+ msg_Dbg( &sys.demuxer, " | | | + fps=%f", float( vfps ) );
+ }
+ else if( EbmlId( *l ) == KaxVideoDisplayUnit::ClassInfos.GlobalId )
+ {
+ KaxVideoDisplayUnit &vdmode = *(KaxVideoDisplayUnit*)l;
+
+ i_display_unit = uint8( vdmode );
+ msg_Dbg( &sys.demuxer, "| | | | + Track Video Display Unit=%s",
+ uint8( vdmode ) == 0 ? "pixels" : ( uint8( vdmode ) == 1 ? "centimeters": "inches" ) );
+ }
+// else if( EbmlId( *l ) == KaxVideoAspectRatio::ClassInfos.GlobalId )
+// {
+// KaxVideoAspectRatio &ratio = *(KaxVideoAspectRatio*)l;
+
+// msg_Dbg( &sys.demuxer, " | | | + Track Video Aspect Ratio Type=%u", uint8( ratio ) );
+// }
+// else if( EbmlId( *l ) == KaxVideoGamma::ClassInfos.GlobalId )
+// {
+// KaxVideoGamma &gamma = *(KaxVideoGamma*)l;
+
+// msg_Dbg( &sys.demuxer, " | | | + gamma=%f", float( gamma ) );
+// }
+ else
+ {
+ msg_Dbg( &sys.demuxer, "| | | | + Unknown (%s)", typeid(*l).name() );
+ }
+ }
+ if( i_display_height && i_display_width )
+ tk->fmt.video.i_aspect = VOUT_ASPECT_FACTOR * i_display_width / i_display_height;
+ if( i_crop_left || i_crop_right || i_crop_top || i_crop_bottom )
+ {
+ tk->fmt.video.i_visible_width = tk->fmt.video.i_width;
+ tk->fmt.video.i_visible_height = tk->fmt.video.i_height;
+ tk->fmt.video.i_x_offset = i_crop_left;
+ tk->fmt.video.i_y_offset = i_crop_top;
+ tk->fmt.video.i_visible_width -= i_crop_left + i_crop_right;
+ tk->fmt.video.i_visible_height -= i_crop_top + i_crop_bottom;
+ }
+ /* FIXME: i_display_* allows you to not only set DAR, but also a zoom factor.
+ we do not support this atm */
+ }
+ else if( MKV_IS_ID( l, KaxTrackAudio ) )
+ {
+ EbmlMaster *tka = static_cast<EbmlMaster*>(l);
+ unsigned int j;
+
+ msg_Dbg( &sys.demuxer, "| | | + Track Audio" );
+
+ for( j = 0; j < tka->ListSize(); j++ )
+ {
+ EbmlElement *l = (*tka)[j];
+
+ if( MKV_IS_ID( l, KaxAudioSamplingFreq ) )
+ {
+ KaxAudioSamplingFreq &afreq = *(KaxAudioSamplingFreq*)l;
+
+ tk->i_original_rate = tk->fmt.audio.i_rate = (int)float( afreq );
+ msg_Dbg( &sys.demuxer, "| | | | + afreq=%d", tk->fmt.audio.i_rate );
+ }
+ else if( MKV_IS_ID( l, KaxAudioOutputSamplingFreq ) )
+ {
+ KaxAudioOutputSamplingFreq &afreq = *(KaxAudioOutputSamplingFreq*)l;
+
+ tk->fmt.audio.i_rate = (int)float( afreq );
+ msg_Dbg( &sys.demuxer, "| | | | + aoutfreq=%d", tk->fmt.audio.i_rate );
+ }
+ else if( MKV_IS_ID( l, KaxAudioChannels ) )
+ {
+ KaxAudioChannels &achan = *(KaxAudioChannels*)l;
+
+ tk->fmt.audio.i_channels = uint8( achan );
+ msg_Dbg( &sys.demuxer, "| | | | + achan=%u", uint8( achan ) );
+ }
+ else if( MKV_IS_ID( l, KaxAudioBitDepth ) )
+ {
+ KaxAudioBitDepth &abits = *(KaxAudioBitDepth*)l;
+
+ tk->fmt.audio.i_bitspersample = uint8( abits );
+ msg_Dbg( &sys.demuxer, "| | | | + abits=%u", uint8( abits ) );
+ }
+ else
+ {
+ msg_Dbg( &sys.demuxer, "| | | | + Unknown (%s)", typeid(*l).name() );
+ }
+ }
+ }
+ else
+ {
+ msg_Dbg( &sys.demuxer, "| | | + Unknown (%s)",
+ typeid(*l).name() );
+ }
+ }
+
+ if ( bSupported )
+ {
+ tracks.push_back( tk );
+ }
+ else
+ {
+ msg_Err( &sys.demuxer, "Track Entry %d not supported", tk->i_number );
+ delete tk;
+ }
+}
+
+/*****************************************************************************
+ * ParseTracks:
+ *****************************************************************************/
+void matroska_segment_c::ParseTracks( KaxTracks *tracks )
+{
+ EbmlElement *el;
+ unsigned int i;
+ int i_upper_level = 0;
+
+ msg_Dbg( &sys.demuxer, "| + Tracks" );
+
+ /* Master elements */
+ tracks->Read( es, tracks->Generic().Context, i_upper_level, el, true );
+
+ for( i = 0; i < tracks->ListSize(); i++ )
+ {
+ EbmlElement *l = (*tracks)[i];
+
+ if( MKV_IS_ID( l, KaxTrackEntry ) )
+ {
+ ParseTrackEntry( static_cast<KaxTrackEntry *>(l) );
+ }
+ else
+ {
+ msg_Dbg( &sys.demuxer, "| | + Unknown (%s)", typeid(*l).name() );
+ }
+ }
+}
+
+/*****************************************************************************
+ * ParseInfo:
+ *****************************************************************************/
+void matroska_segment_c::ParseInfo( KaxInfo *info )
+{
+ EbmlElement *el;
+ EbmlMaster *m;
+ size_t i, j;
+ int i_upper_level = 0;
+
+ msg_Dbg( &sys.demuxer, "| + Information" );
+
+ /* Master elements */
+ m = static_cast<EbmlMaster *>(info);
+ m->Read( es, info->Generic().Context, i_upper_level, el, true );
+
+ for( i = 0; i < m->ListSize(); i++ )
+ {
+ EbmlElement *l = (*m)[i];
+
+ if( MKV_IS_ID( l, KaxSegmentUID ) )
+ {
+ if ( p_segment_uid == NULL )
+ p_segment_uid = new KaxSegmentUID(*static_cast<KaxSegmentUID*>(l));
+
+ msg_Dbg( &sys.demuxer, "| | + UID=%d", *(uint32*)p_segment_uid->GetBuffer() );
+ }
+ else if( MKV_IS_ID( l, KaxPrevUID ) )
+ {
+ if ( p_prev_segment_uid == NULL )
+ p_prev_segment_uid = new KaxPrevUID(*static_cast<KaxPrevUID*>(l));
+
+ msg_Dbg( &sys.demuxer, "| | + PrevUID=%d", *(uint32*)p_prev_segment_uid->GetBuffer() );
+ }
+ else if( MKV_IS_ID( l, KaxNextUID ) )
+ {
+ if ( p_next_segment_uid == NULL )
+ p_next_segment_uid = new KaxNextUID(*static_cast<KaxNextUID*>(l));
+
+ msg_Dbg( &sys.demuxer, "| | + NextUID=%d", *(uint32*)p_next_segment_uid->GetBuffer() );
+ }
+ else if( MKV_IS_ID( l, KaxTimecodeScale ) )
+ {
+ KaxTimecodeScale &tcs = *(KaxTimecodeScale*)l;
+
+ i_timescale = uint64(tcs);
+
+ msg_Dbg( &sys.demuxer, "| | + TimecodeScale="I64Fd,
+ i_timescale );
+ }
+ else if( MKV_IS_ID( l, KaxDuration ) )
+ {
+ KaxDuration &dur = *(KaxDuration*)l;
+
+ i_duration = mtime_t( double( dur ) );
+
+ msg_Dbg( &sys.demuxer, "| | + Duration="I64Fd,
+ i_duration );
+ }
+ else if( MKV_IS_ID( l, KaxMuxingApp ) )
+ {
+ KaxMuxingApp &mapp = *(KaxMuxingApp*)l;
+
+ psz_muxing_application = ToUTF8( UTFstring( mapp ) );
+
+ msg_Dbg( &sys.demuxer, "| | + Muxing Application=%s",
+ psz_muxing_application );
+ }
+ else if( MKV_IS_ID( l, KaxWritingApp ) )
+ {
+ KaxWritingApp &wapp = *(KaxWritingApp*)l;
+
+ psz_writing_application = ToUTF8( UTFstring( wapp ) );
+
+ msg_Dbg( &sys.demuxer, "| | + Writing Application=%s",
+ psz_writing_application );
+ }
+ else if( MKV_IS_ID( l, KaxSegmentFilename ) )
+ {
+ KaxSegmentFilename &sfn = *(KaxSegmentFilename*)l;
+
+ psz_segment_filename = ToUTF8( UTFstring( sfn ) );
+
+ msg_Dbg( &sys.demuxer, "| | + Segment Filename=%s",
+ psz_segment_filename );
+ }
+ else if( MKV_IS_ID( l, KaxTitle ) )
+ {
+ KaxTitle &title = *(KaxTitle*)l;
+
+ psz_title = ToUTF8( UTFstring( title ) );
+
+ msg_Dbg( &sys.demuxer, "| | + Title=%s", psz_title );
+ }
+ else if( MKV_IS_ID( l, KaxSegmentFamily ) )
+ {
+ KaxSegmentFamily *uid = static_cast<KaxSegmentFamily*>(l);
+
+ families.push_back( new KaxSegmentFamily(*uid) );
+
+ msg_Dbg( &sys.demuxer, "| | + family=%d", *(uint32*)uid->GetBuffer() );
+ }
+#if defined( HAVE_GMTIME_R ) && !defined( __APPLE__ )
+ else if( MKV_IS_ID( l, KaxDateUTC ) )
+ {
+ KaxDateUTC &date = *(KaxDateUTC*)l;
+ time_t i_date;
+ struct tm tmres;
+ char buffer[256];
+
+ i_date = date.GetEpochDate();
+ memset( buffer, 0, 256 );
+ if( gmtime_r( &i_date, &tmres ) &&
+ asctime_r( &tmres, buffer ) )
+ {
+ buffer[strlen( buffer)-1]= '\0';
+ psz_date_utc = strdup( buffer );
+ msg_Dbg( &sys.demuxer, "| | + Date=%s", psz_date_utc );
+ }
+ }
+#endif
+#if LIBMATROSKA_VERSION >= 0x000704
+ else if( MKV_IS_ID( l, KaxChapterTranslate ) )
+ {
+ KaxChapterTranslate *p_trans = static_cast<KaxChapterTranslate*>( l );
+ chapter_translation_c *p_translate = new chapter_translation_c();
+
+ p_trans->Read( es, p_trans->Generic().Context, i_upper_level, el, true );
+ for( j = 0; j < p_trans->ListSize(); j++ )
+ {
+ EbmlElement *l = (*p_trans)[j];
+
+ if( MKV_IS_ID( l, KaxChapterTranslateEditionUID ) )
+ {
+ p_translate->editions.push_back( uint64( *static_cast<KaxChapterTranslateEditionUID*>( l ) ) );
+ }
+ else if( MKV_IS_ID( l, KaxChapterTranslateCodec ) )
+ {
+ p_translate->codec_id = uint32( *static_cast<KaxChapterTranslateCodec*>( l ) );
+ }
+ else if( MKV_IS_ID( l, KaxChapterTranslateID ) )
+ {
+ p_translate->p_translated = new KaxChapterTranslateID( *static_cast<KaxChapterTranslateID*>( l ) );
+ }
+ }
+
+ translations.push_back( p_translate );
+ }
+#endif
+ else
+ {
+ msg_Dbg( &sys.demuxer, "| | + Unknown (%s)", typeid(*l).name() );
+ }
+ }
+
+ double f_dur = double(i_duration) * double(i_timescale) / 1000000.0;
+ i_duration = mtime_t(f_dur);
+}
+
+
+/*****************************************************************************
+ * ParseChapterAtom
+ *****************************************************************************/
+void matroska_segment_c::ParseChapterAtom( int i_level, KaxChapterAtom *ca, chapter_item_c & chapters )
+{
+ size_t i, j;
+
+ msg_Dbg( &sys.demuxer, "| | | + ChapterAtom (level=%d)", i_level );
+ for( i = 0; i < ca->ListSize(); i++ )
+ {
+ EbmlElement *l = (*ca)[i];
+
+ if( MKV_IS_ID( l, KaxChapterUID ) )
+ {
+ chapters.i_uid = uint64_t(*(KaxChapterUID*)l);
+ msg_Dbg( &sys.demuxer, "| | | | + ChapterUID: %lld", chapters.i_uid );
+ }
+ else if( MKV_IS_ID( l, KaxChapterFlagHidden ) )
+ {
+ KaxChapterFlagHidden &flag =*(KaxChapterFlagHidden*)l;
+ chapters.b_display_seekpoint = uint8( flag ) == 0;
+
+ msg_Dbg( &sys.demuxer, "| | | | + ChapterFlagHidden: %s", chapters.b_display_seekpoint ? "no":"yes" );
+ }
+ else if( MKV_IS_ID( l, KaxChapterTimeStart ) )
+ {
+ KaxChapterTimeStart &start =*(KaxChapterTimeStart*)l;
+ chapters.i_start_time = uint64( start ) / I64C(1000);
+
+ msg_Dbg( &sys.demuxer, "| | | | + ChapterTimeStart: %lld", chapters.i_start_time );
+ }
+ else if( MKV_IS_ID( l, KaxChapterTimeEnd ) )
+ {
+ KaxChapterTimeEnd &end =*(KaxChapterTimeEnd*)l;
+ chapters.i_end_time = uint64( end ) / I64C(1000);
+
+ msg_Dbg( &sys.demuxer, "| | | | + ChapterTimeEnd: %lld", chapters.i_end_time );
+ }
+ else if( MKV_IS_ID( l, KaxChapterDisplay ) )
+ {
+ EbmlMaster *cd = static_cast<EbmlMaster *>(l);
+
+ msg_Dbg( &sys.demuxer, "| | | | + ChapterDisplay" );
+ for( j = 0; j < cd->ListSize(); j++ )
+ {
+ EbmlElement *l= (*cd)[j];
+
+ if( MKV_IS_ID( l, KaxChapterString ) )
+ {
+ int k;
+
+ KaxChapterString &name =*(KaxChapterString*)l;
+ for (k = 0; k < i_level; k++)
+ chapters.psz_name += '+';
+ chapters.psz_name += ' ';
+ char *psz_tmp_utf8 = ToUTF8( UTFstring( name ) );
+ chapters.psz_name += psz_tmp_utf8;
+ chapters.b_user_display = true;
+
+ msg_Dbg( &sys.demuxer, "| | | | | + ChapterString '%s'", psz_tmp_utf8 );
+ free( psz_tmp_utf8 );
+ }
+ else if( MKV_IS_ID( l, KaxChapterLanguage ) )
+ {
+ KaxChapterLanguage &lang =*(KaxChapterLanguage*)l;
+ const char *psz = string( lang ).c_str();
+
+ msg_Dbg( &sys.demuxer, "| | | | | + ChapterLanguage '%s'", psz );
+ }
+ else if( MKV_IS_ID( l, KaxChapterCountry ) )
+ {
+ KaxChapterCountry &ct =*(KaxChapterCountry*)l;
+ const char *psz = string( ct ).c_str();
+
+ msg_Dbg( &sys.demuxer, "| | | | | + ChapterCountry '%s'", psz );
+ }
+ }
+ }
+ else if( MKV_IS_ID( l, KaxChapterProcess ) )
+ {
+ msg_Dbg( &sys.demuxer, "| | | | + ChapterProcess" );
+
+ KaxChapterProcess *cp = static_cast<KaxChapterProcess *>(l);
+ chapter_codec_cmds_c *p_ccodec = NULL;
+
+ for( j = 0; j < cp->ListSize(); j++ )
+ {
+ EbmlElement *k= (*cp)[j];
+
+ if( MKV_IS_ID( k, KaxChapterProcessCodecID ) )
+ {
+ KaxChapterProcessCodecID *p_codec_id = static_cast<KaxChapterProcessCodecID*>( k );
+ if ( uint32(*p_codec_id) == 0 )
+ p_ccodec = new matroska_script_codec_c( sys );
+ else if ( uint32(*p_codec_id) == 1 )
+ p_ccodec = new dvd_chapter_codec_c( sys );
+ break;
+ }
+ }
+
+ if ( p_ccodec != NULL )
+ {
+ for( j = 0; j < cp->ListSize(); j++ )
+ {
+ EbmlElement *k= (*cp)[j];
+
+ if( MKV_IS_ID( k, KaxChapterProcessPrivate ) )
+ {
+ KaxChapterProcessPrivate * p_private = static_cast<KaxChapterProcessPrivate*>( k );
+ p_ccodec->SetPrivate( *p_private );
+ }
+ else if( MKV_IS_ID( k, KaxChapterProcessCommand ) )
+ {
+ p_ccodec->AddCommand( *static_cast<KaxChapterProcessCommand*>( k ) );
+ }
+ }
+ chapters.codecs.push_back( p_ccodec );
+ }
+ }
+ else if( MKV_IS_ID( l, KaxChapterAtom ) )
+ {
+ chapter_item_c *new_sub_chapter = new chapter_item_c();
+ ParseChapterAtom( i_level+1, static_cast<KaxChapterAtom *>(l), *new_sub_chapter );
+ new_sub_chapter->psz_parent = &chapters;
+ chapters.sub_chapters.push_back( new_sub_chapter );
+ }
+ }
+}
+
+/*****************************************************************************
+ * ParseAttachments:
+ *****************************************************************************/
+void matroska_segment_c::ParseAttachments( KaxAttachments *attachments )
+{
+ EbmlElement *el;
+ int i_upper_level = 0;
+
+ attachments->Read( es, attachments->Generic().Context, i_upper_level, el, true );
+
+ KaxAttached *attachedFile = FindChild<KaxAttached>( *attachments );
+
+ while( attachedFile && ( attachedFile->GetSize() > 0 ) )
+ {
+ std::string psz_mime_type = GetChild<KaxMimeType>( *attachedFile );
+ KaxFileName &file_name = GetChild<KaxFileName>( *attachedFile );
+ KaxFileData &img_data = GetChild<KaxFileData>( *attachedFile );
+
+ attachment_c *new_attachment = new attachment_c();
+
+ if( new_attachment )
+ {
+ new_attachment->psz_file_name = ToUTF8( UTFstring( file_name ) );
+ new_attachment->psz_mime_type = psz_mime_type;
+ new_attachment->i_size = img_data.GetSize();
+ new_attachment->p_data = malloc( img_data.GetSize() );
+
+ if( new_attachment->p_data )
+ {
+ memcpy( new_attachment->p_data, img_data.GetBuffer(), img_data.GetSize() );
+ sys.stored_attachments.push_back( new_attachment );
+ }
+ else
+ {
+ delete new_attachment;
+ }
+ }
+
+ attachedFile = &GetNextChild<KaxAttached>( *attachments, *attachedFile );
+ }
+}
+
+/*****************************************************************************
+ * ParseChapters:
+ *****************************************************************************/
+void matroska_segment_c::ParseChapters( KaxChapters *chapters )
+{
+ EbmlElement *el;
+ size_t i;
+ int i_upper_level = 0;
+ mtime_t i_dur;
+
+ /* Master elements */
+ chapters->Read( es, chapters->Generic().Context, i_upper_level, el, true );
+
+ for( i = 0; i < chapters->ListSize(); i++ )
+ {
+ EbmlElement *l = (*chapters)[i];
+
+ if( MKV_IS_ID( l, KaxEditionEntry ) )
+ {
+ chapter_edition_c *p_edition = new chapter_edition_c();
+
+ EbmlMaster *E = static_cast<EbmlMaster *>(l );
+ size_t j;
+ msg_Dbg( &sys.demuxer, "| | + EditionEntry" );
+ for( j = 0; j < E->ListSize(); j++ )
+ {
+ EbmlElement *l = (*E)[j];
+
+ if( MKV_IS_ID( l, KaxChapterAtom ) )
+ {
+ chapter_item_c *new_sub_chapter = new chapter_item_c();
+ ParseChapterAtom( 0, static_cast<KaxChapterAtom *>(l), *new_sub_chapter );
+ p_edition->sub_chapters.push_back( new_sub_chapter );
+ }
+ else if( MKV_IS_ID( l, KaxEditionUID ) )
+ {
+ p_edition->i_uid = uint64(*static_cast<KaxEditionUID *>( l ));
+ }
+ else if( MKV_IS_ID( l, KaxEditionFlagOrdered ) )
+ {
+ p_edition->b_ordered = config_GetInt( &sys.demuxer, "mkv-use-ordered-chapters" ) ? (uint8(*static_cast<KaxEditionFlagOrdered *>( l )) != 0) : 0;
+ }
+ else if( MKV_IS_ID( l, KaxEditionFlagDefault ) )
+ {
+ if (uint8(*static_cast<KaxEditionFlagDefault *>( l )) != 0)
+ i_default_edition = stored_editions.size();
+ }
+ else
+ {
+ msg_Dbg( &sys.demuxer, "| | | + Unknown (%s)", typeid(*l).name() );
+ }
+ }
+ stored_editions.push_back( p_edition );
+ }
+ else
+ {
+ msg_Dbg( &sys.demuxer, "| | + Unknown (%s)", typeid(*l).name() );
+ }
+ }
+
+ for( i = 0; i < stored_editions.size(); i++ )
+ {
+ stored_editions[i]->RefreshChapters( );
+ }
+
+ if ( stored_editions.size() != 0 && stored_editions[i_default_edition]->b_ordered )
+ {
+ /* update the duration of the segment according to the sum of all sub chapters */
+ i_dur = stored_editions[i_default_edition]->Duration() / I64C(1000);
+ if (i_dur > 0)
+ i_duration = i_dur;
+ }
+}
+
+void matroska_segment_c::ParseCluster( )
+{
+ EbmlElement *el;
+ EbmlMaster *m;
+ unsigned int i;
+ int i_upper_level = 0;
+
+ /* Master elements */
+ m = static_cast<EbmlMaster *>( cluster );
+ m->Read( es, cluster->Generic().Context, i_upper_level, el, true );
+
+ for( i = 0; i < m->ListSize(); i++ )
+ {
+ EbmlElement *l = (*m)[i];
+
+ if( MKV_IS_ID( l, KaxClusterTimecode ) )
+ {
+ KaxClusterTimecode &ctc = *(KaxClusterTimecode*)l;
+
+ cluster->InitTimecode( uint64( ctc ), i_timescale );
+ break;
+ }
+ }
+
+ i_start_time = cluster->GlobalTimecode() / 1000;
+}
+
+/*****************************************************************************
+ * InformationCreate:
+ *****************************************************************************/
+void matroska_segment_c::InformationCreate( )
+{
+ sys.meta = vlc_meta_New();
+
+ if( psz_title )
+ {
+ vlc_meta_SetTitle( sys.meta, psz_title );
+ }
+ if( psz_date_utc )
+ {
+ vlc_meta_SetDate( sys.meta, psz_date_utc );
+ }
+#if 0
+ if( psz_segment_filename )
+ {
+ fprintf( stderr, "***** WARNING: Unhandled meta - Use custom\n" );
+ }
+ if( psz_muxing_application )
+ {
+ fprintf( stderr, "***** WARNING: Unhandled meta - Use custom\n" );
+ }
+ if( psz_writing_application )
+ {
+ fprintf( stderr, "***** WARNING: Unhandled meta - Use custom\n" );
+ }
+
+ for( size_t i_track = 0; i_track < tracks.size(); i_track++ )
+ {
+// mkv_track_t *tk = tracks[i_track];
+// vlc_meta_t *mtk = vlc_meta_New();
+ fprintf( stderr, "***** WARNING: Unhandled child meta\n");
+ }
+#endif
+
+ if( i_tags_position >= 0 )
+ {
+ vlc_bool_t b_seekable;
+
+ stream_Control( sys.demuxer.s, STREAM_CAN_FASTSEEK, &b_seekable );
+ if( b_seekable )
+ {
+ LoadTags( );
+ }
+ }
+}
+
+
+/*****************************************************************************
+ * Divers
+ *****************************************************************************/
+
+void matroska_segment_c::IndexAppendCluster( KaxCluster *cluster )
+{
+#define idx p_indexes[i_index]
+ idx.i_track = -1;
+ idx.i_block_number= -1;
+ idx.i_position = cluster->GetElementPosition();
+ idx.i_time = -1;
+ idx.b_key = VLC_TRUE;
+
+ i_index++;
+ if( i_index >= i_index_max )
+ {
+ i_index_max += 1024;
+ p_indexes = (mkv_index_t*)realloc( p_indexes, sizeof( mkv_index_t ) * i_index_max );
+ }
+#undef idx
+}
+
+void chapter_edition_c::RefreshChapters( )
+{
+ chapter_item_c::RefreshChapters( b_ordered, -1 );
+ b_display_seekpoint = false;
+}
+
+int64_t chapter_item_c::RefreshChapters( bool b_ordered, int64_t i_prev_user_time )
+{
+ int64_t i_user_time = i_prev_user_time;
+
+ // first the sub-chapters, and then ourself
+ std::vector<chapter_item_c*>::iterator index = sub_chapters.begin();
+ while ( index != sub_chapters.end() )
+ {
+ i_user_time = (*index)->RefreshChapters( b_ordered, i_user_time );
+ index++;
+ }
+
+ if ( b_ordered )
+ {
+ // the ordered chapters always start at zero
+ if ( i_prev_user_time == -1 )
+ {
+ if ( i_user_time == -1 )
+ i_user_time = 0;
+ i_prev_user_time = 0;
+ }
+
+ i_user_start_time = i_prev_user_time;
+ if ( i_end_time != -1 && i_user_time == i_prev_user_time )
+ {
+ i_user_end_time = i_user_start_time - i_start_time + i_end_time;
+ }
+ else
+ {
+ i_user_end_time = i_user_time;
+ }
+ }
+ else
+ {
+ if ( sub_chapters.begin() != sub_chapters.end() )
+ std::sort( sub_chapters.begin(), sub_chapters.end(), chapter_item_c::CompareTimecode );
+ i_user_start_time = i_start_time;
+ if ( i_end_time != -1 )
+ i_user_end_time = i_end_time;
+ else if ( i_user_time != -1 )
+ i_user_end_time = i_user_time;
+ else
+ i_user_end_time = i_user_start_time;
+ }
+
+ return i_user_end_time;
+}
+
+mtime_t chapter_edition_c::Duration() const
+{
+ mtime_t i_result = 0;
+
+ if ( sub_chapters.size() )
+ {
+ std::vector<chapter_item_c*>::const_iterator index = sub_chapters.end();
+ index--;
+ i_result = (*index)->i_user_end_time;
+ }
+
+ return i_result;
+}
+
+chapter_item_c * chapter_edition_c::FindTimecode( mtime_t i_timecode, const chapter_item_c * p_current )
+{
+ if ( !b_ordered )
+ p_current = NULL;
+ bool b_found_current = false;
+ return chapter_item_c::FindTimecode( i_timecode, p_current, b_found_current );
+}
+
+chapter_item_c *chapter_item_c::FindTimecode( mtime_t i_user_timecode, const chapter_item_c * p_current, bool & b_found )
+{
+ chapter_item_c *psz_result = NULL;
+
+ if ( p_current == this )
+ b_found = true;
+
+ if ( i_user_timecode >= i_user_start_time &&
+ ( i_user_timecode < i_user_end_time ||
+ ( i_user_start_time == i_user_end_time && i_user_timecode == i_user_end_time )))
+ {
+ std::vector<chapter_item_c*>::iterator index = sub_chapters.begin();
+ while ( index != sub_chapters.end() && ((p_current == NULL && psz_result == NULL) || (p_current != NULL && (!b_found || psz_result == NULL))))
+ {
+ psz_result = (*index)->FindTimecode( i_user_timecode, p_current, b_found );
+ index++;
+ }
+
+ if ( psz_result == NULL )
+ psz_result = this;
+ }
+
+ return psz_result;
+}
+
+bool chapter_item_c::ParentOf( const chapter_item_c & item ) const
+{
+ if ( &item == this )
+ return true;
+
+ std::vector<chapter_item_c*>::const_iterator index = sub_chapters.begin();
+ while ( index != sub_chapters.end() )
+ {
+ if ( (*index)->ParentOf( item ) )
+ return true;
+ index++;
+ }
+
+ return false;
+}
+
+void demux_sys_t::PreloadFamily( const matroska_segment_c & of_segment )
+{
+ for (size_t i=0; i<opened_segments.size(); i++)
+ {
+ opened_segments[i]->PreloadFamily( of_segment );
+ }
+}
+bool matroska_segment_c::PreloadFamily( const matroska_segment_c & of_segment )
+{
+ if ( b_preloaded )
+ return false;
+
+ for (size_t i=0; i<families.size(); i++)
+ {
+ for (size_t j=0; j<of_segment.families.size(); j++)
+ {
+ if ( *(families[i]) == *(of_segment.families[j]) )
+ return Preload( );
+ }
+ }
+
+ return false;
+}
+
+// preload all the linked segments for all preloaded segments
+void demux_sys_t::PreloadLinked( matroska_segment_c *p_segment )
+{
+ size_t i_preloaded, i, j;
+ virtual_segment_c *p_seg;
+
+ p_current_segment = VirtualFromSegments( p_segment );
+
+ used_segments.push_back( p_current_segment );
+
+ // create all the other virtual segments of the family
+ do {
+ i_preloaded = 0;
+ for ( i=0; i< opened_segments.size(); i++ )
+ {
+ if ( opened_segments[i]->b_preloaded && !IsUsedSegment( *opened_segments[i] ) )
+ {
+ p_seg = VirtualFromSegments( opened_segments[i] );
+ used_segments.push_back( p_seg );
+ i_preloaded++;
+ }
+ }
+ } while ( i_preloaded ); // worst case: will stop when all segments are found as family related
+
+ // publish all editions of all usable segment
+ for ( i=0; i< used_segments.size(); i++ )
+ {
+ p_seg = used_segments[i];
+ if ( p_seg->p_editions != NULL )
+ {
+ std::string sz_name;
+ input_title_t *p_title = vlc_input_title_New();
+ p_seg->i_sys_title = i;
+ int i_chapters;
+
+ // TODO use a name for each edition, let the TITLE deal with a codec name
+ for ( j=0; j<p_seg->p_editions->size(); j++ )
+ {
+ if ( p_title->psz_name == NULL )
+ {
+ sz_name = (*p_seg->p_editions)[j]->GetMainName();
+ if ( sz_name != "" )
+ p_title->psz_name = strdup( sz_name.c_str() );
+ }
+
+ chapter_edition_c *p_edition = (*p_seg->p_editions)[j];
+
+ i_chapters = 0;
+ p_edition->PublishChapters( *p_title, i_chapters, 0 );
+ }
+
+ // create a name if there is none
+ if ( p_title->psz_name == NULL )
+ {
+ sz_name = N_("Segment");
+ char psz_str[6];
+ sprintf( psz_str, " %d", (int)i );
+ sz_name += psz_str;
+ p_title->psz_name = strdup( sz_name.c_str() );
+ }
+
+ titles.push_back( p_title );
+ }
+ }
+
+ // TODO decide which segment should be first used (VMG for DVD)
+}
+
+bool demux_sys_t::IsUsedSegment( matroska_segment_c &segment ) const
+{
+ for ( size_t i=0; i< used_segments.size(); i++ )
+ {
+ if ( used_segments[i]->FindUID( *segment.p_segment_uid ) )
+ return true;
+ }
+ return false;
+}
+
+virtual_segment_c *demux_sys_t::VirtualFromSegments( matroska_segment_c *p_segment ) const
+{
+ size_t i_preloaded, i;
+
+ virtual_segment_c *p_result = new virtual_segment_c( p_segment );
+
+ // fill our current virtual segment with all hard linked segments
+ do {
+ i_preloaded = 0;
+ for ( i=0; i< opened_segments.size(); i++ )
+ {
+ i_preloaded += p_result->AddSegment( opened_segments[i] );
+ }
+ } while ( i_preloaded ); // worst case: will stop when all segments are found as linked
+
+ p_result->Sort( );
+
+ p_result->PreloadLinked( );
+
+ p_result->PrepareChapters( );
+
+ return p_result;
+}
+
+bool demux_sys_t::PreparePlayback( virtual_segment_c *p_new_segment )
+{
+ if ( p_new_segment != NULL && p_new_segment != p_current_segment )
+ {
+ if ( p_current_segment != NULL && p_current_segment->Segment() != NULL )
+ p_current_segment->Segment()->UnSelect();
+
+ p_current_segment = p_new_segment;
+ i_current_title = p_new_segment->i_sys_title;
+ }
+
+ p_current_segment->LoadCues();
+ f_duration = p_current_segment->Duration();
+
+ /* add information */
+ p_current_segment->Segment()->InformationCreate( );
+
+ p_current_segment->Segment()->Select( 0 );
+
+ return true;
+}
+
+void demux_sys_t::JumpTo( virtual_segment_c & vsegment, chapter_item_c * p_chapter )
+{
+ // if the segment is not part of the current segment, select the new one
+ if ( &vsegment != p_current_segment )
+ {
+ PreparePlayback( &vsegment );
+ }
+
+ if ( p_chapter != NULL )
+ {
+ if ( !p_chapter->Enter( true ) )
+ {
+ // jump to the location in the found segment
+ vsegment.Seek( demuxer, p_chapter->i_user_start_time, -1, p_chapter );
+ }
+ }
+
+}
+
+bool matroska_segment_c::CompareSegmentUIDs( const matroska_segment_c * p_item_a, const matroska_segment_c * p_item_b )
+{
+ EbmlBinary *p_tmp;
+
+ if ( p_item_a == NULL || p_item_b == NULL )
+ return false;
+
+ p_tmp = (EbmlBinary *)p_item_a->p_segment_uid;
+ if ( p_item_b->p_prev_segment_uid != NULL
+ && *p_tmp == *p_item_b->p_prev_segment_uid )
+ return true;
+
+ p_tmp = (EbmlBinary *)p_item_a->p_next_segment_uid;
+ if ( !p_tmp )
+ return false;
+
+ if ( p_item_b->p_segment_uid != NULL
+ && *p_tmp == *p_item_b->p_segment_uid )
+ return true;
+
+ if ( p_item_b->p_prev_segment_uid != NULL
+ && *p_tmp == *p_item_b->p_prev_segment_uid )
+ return true;
+
+ return false;
+}
+
+bool matroska_segment_c::Preload( )
+{
+ if ( b_preloaded )
+ return false;
+
+ EbmlElement *el = NULL;
+
+ ep->Reset( &sys.demuxer );
+
+ while( ( el = ep->Get() ) != NULL )
+ {
+ if( MKV_IS_ID( el, KaxInfo ) )
+ {
+ ParseInfo( static_cast<KaxInfo*>( el ) );
+ }
+ else if( MKV_IS_ID( el, KaxTracks ) )
+ {
+ ParseTracks( static_cast<KaxTracks*>( el ) );
+ if ( tracks.size() == 0 )
+ {
+ msg_Err( &sys.demuxer, "No tracks supported" );
+ return false;
+ }
+ }
+ else if( MKV_IS_ID( el, KaxSeekHead ) )
+ {
+ ParseSeekHead( static_cast<KaxSeekHead*>( el ) );
+ }
+ else if( MKV_IS_ID( el, KaxCues ) )
+ {
+ msg_Dbg( &sys.demuxer, "| + Cues" );
+ }
+ else if( MKV_IS_ID( el, KaxCluster ) )
+ {
+ msg_Dbg( &sys.demuxer, "| + Cluster" );
+
+ cluster = (KaxCluster*)el;
+
+ i_cluster_pos = i_start_pos = cluster->GetElementPosition();
+ ParseCluster( );
+
+ ep->Down();
+ /* stop parsing the stream */
+ break;
+ }
+ else if( MKV_IS_ID( el, KaxAttachments ) )
+ {
+ msg_Dbg( &sys.demuxer, "| + Attachments" );
+ ParseAttachments( static_cast<KaxAttachments*>( el ) );
+ }
+ else if( MKV_IS_ID( el, KaxChapters ) )
+ {
+ msg_Dbg( &sys.demuxer, "| + Chapters" );
+ ParseChapters( static_cast<KaxChapters*>( el ) );