+}
+
+/*****************************************************************************
+ * ParseTracks:
+ *****************************************************************************/
+static void ParseTrackEntry( demux_t *p_demux, EbmlMaster *m )
+{
+ demux_sys_t *p_sys = p_demux->p_sys;
+ unsigned int i;
+
+ mkv_track_t *tk;
+
+ msg_Dbg( p_demux, "| | + Track Entry" );
+
+ p_sys->i_track++;
+ p_sys->track = (mkv_track_t*)realloc( p_sys->track, sizeof( mkv_track_t ) * (p_sys->i_track + 1 ) );
+
+ /* Init the track */
+ tk = &p_sys->track[p_sys->i_track - 1];
+
+ 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->i_number = p_sys->i_track - 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;
+
+ 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( p_demux, "| | | + Track Number=%u", uint32( tnum ) );
+ }
+ else if( MKV_IS_ID( l, KaxTrackUID ) )
+ {
+ KaxTrackUID &tuid = *(KaxTrackUID*)l;
+
+ msg_Dbg( p_demux, "| | | + Track UID=%u", uint32( tuid ) );
+ }
+ else if( MKV_IS_ID( l, KaxTrackType ) )
+ {
+ 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;
+ default:
+ psz_type = "unknown";
+ tk->fmt.i_cat = UNKNOWN_ES;
+ break;
+ }
+
+ msg_Dbg( p_demux, "| | | + Track Type=%s", psz_type );
+ }
+// else if( EbmlId( *l ) == KaxTrackFlagEnabled::ClassInfos.GlobalId )
+// {
+// KaxTrackFlagEnabled &fenb = *(KaxTrackFlagEnabled*)l;
+
+// tk->b_enabled = uint32( fenb );
+// msg_Dbg( p_demux, "| | | + Track Enabled=%u",
+// uint32( fenb ) );
+// }
+ else if( MKV_IS_ID( l, KaxTrackFlagDefault ) )
+ {
+ KaxTrackFlagDefault &fdef = *(KaxTrackFlagDefault*)l;
+
+ tk->b_default = uint32( fdef );
+ msg_Dbg( p_demux, "| | | + Track Default=%u", uint32( fdef ) );
+ }
+ else if( MKV_IS_ID( l, KaxTrackFlagLacing ) )
+ {
+ KaxTrackFlagLacing &lac = *(KaxTrackFlagLacing*)l;
+
+ msg_Dbg( p_demux, "| | | + Track Lacing=%d", uint32( lac ) );
+ }
+ else if( MKV_IS_ID( l, KaxTrackMinCache ) )
+ {
+ KaxTrackMinCache &cmin = *(KaxTrackMinCache*)l;
+
+ msg_Dbg( p_demux, "| | | + Track MinCache=%d", uint32( cmin ) );
+ }
+ else if( MKV_IS_ID( l, KaxTrackMaxCache ) )
+ {
+ KaxTrackMaxCache &cmax = *(KaxTrackMaxCache*)l;
+
+ msg_Dbg( p_demux, "| | | + Track MaxCache=%d", uint32( cmax ) );
+ }
+ else if( MKV_IS_ID( l, KaxTrackDefaultDuration ) )
+ {
+ KaxTrackDefaultDuration &defd = *(KaxTrackDefaultDuration*)l;
+
+ tk->i_default_duration = uint64(defd);
+ msg_Dbg( p_demux, "| | | + Track Default Duration="I64Fd, uint64(defd) );
+ }
+ else if( MKV_IS_ID( l, KaxTrackTimecodeScale ) )
+ {
+ KaxTrackTimecodeScale &ttcs = *(KaxTrackTimecodeScale*)l;
+
+ tk->f_timecodescale = float( ttcs );
+ msg_Dbg( p_demux, "| | | + Track TimeCodeScale=%f", tk->f_timecodescale );
+ }
+ else if( MKV_IS_ID( l, KaxTrackName ) )
+ {
+ KaxTrackName &tname = *(KaxTrackName*)l;
+
+ tk->fmt.psz_description = UTF8ToStr( UTFstring( tname ) );
+ msg_Dbg( p_demux, "| | | + Track Name=%s", tk->fmt.psz_description );
+ }
+ else if( MKV_IS_ID( l, KaxTrackLanguage ) )
+ {
+ KaxTrackLanguage &lang = *(KaxTrackLanguage*)l;
+
+ tk->fmt.psz_language = strdup( string( lang ).c_str() );
+ msg_Dbg( p_demux,
+ "| | | + 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( p_demux, "| | | + 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( p_demux, "| | | + Track CodecPrivate size="I64Fd, cpriv.GetSize() );
+ }
+ else if( MKV_IS_ID( l, KaxCodecName ) )
+ {
+ KaxCodecName &cname = *(KaxCodecName*)l;
+
+ tk->psz_codec_name = UTF8ToStr( UTFstring( cname ) );
+ msg_Dbg( p_demux, "| | | + Track Codec Name=%s", tk->psz_codec_name );
+ }
+ else if( MKV_IS_ID( l, KaxContentEncodings ) )
+ {
+ EbmlMaster *cencs = static_cast<EbmlMaster*>(l);
+ MkvTree( p_demux, 3, "Content Encodings" );
+ for( unsigned int i = 0; i < cencs->ListSize(); i++ )
+ {
+ EbmlElement *l2 = (*cencs)[i];
+ if( MKV_IS_ID( l2, KaxContentEncoding ) )
+ {
+ MkvTree( p_demux, 4, "Content Encoding" );
+ EbmlMaster *cenc = static_cast<EbmlMaster*>(l2);
+ for( unsigned int i = 0; i < cenc->ListSize(); i++ )
+ {
+ EbmlElement *l3 = (*cenc)[i];
+ if( MKV_IS_ID( l3, KaxContentEncodingOrder ) )
+ {
+ KaxContentEncodingOrder &encord = *(KaxContentEncodingOrder*)l3;
+ MkvTree( p_demux, 5, "Order: %i", uint32( encord ) );
+ }
+ else if( MKV_IS_ID( l3, KaxContentEncodingScope ) )
+ {
+ KaxContentEncodingScope &encscope = *(KaxContentEncodingScope*)l3;
+ MkvTree( p_demux, 5, "Scope: %i", uint32( encscope ) );
+ }
+ else if( MKV_IS_ID( l3, KaxContentEncodingType ) )
+ {
+ KaxContentEncodingType &enctype = *(KaxContentEncodingType*)l3;
+ MkvTree( p_demux, 5, "Type: %i", uint32( enctype ) );
+ }
+ else if( MKV_IS_ID( l3, KaxContentCompression ) )
+ {
+ EbmlMaster *compr = static_cast<EbmlMaster*>(l3);
+ MkvTree( p_demux, 5, "Content Compression" );
+ for( unsigned int i = 0; i < compr->ListSize(); i++ )
+ {
+ EbmlElement *l4 = (*compr)[i];
+ if( MKV_IS_ID( l4, KaxContentCompAlgo ) )
+ {
+ KaxContentCompAlgo &compalg = *(KaxContentCompAlgo*)l4;
+ MkvTree( p_demux, 6, "Compression Algorithm: %i", uint32(compalg) );
+ if( uint32( compalg ) == 0 )
+ {
+ tk->i_compression_type = MATROSKA_COMPRESSION_ZLIB;
+ }
+ }
+ else
+ {
+ MkvTree( p_demux, 6, "Unknown (%s)", typeid(*l4).name() );
+ }
+ }
+ }
+
+ else
+ {
+ MkvTree( p_demux, 5, "Unknown (%s)", typeid(*l3).name() );
+ }
+ }
+
+ }
+ else
+ {
+ MkvTree( p_demux, 4, "Unknown (%s)", typeid(*l2).name() );
+ }
+ }
+
+ }
+// else if( EbmlId( *l ) == KaxCodecSettings::ClassInfos.GlobalId )
+// {
+// KaxCodecSettings &cset = *(KaxCodecSettings*)l;
+
+// tk->psz_codec_settings = UTF8ToStr( UTFstring( cset ) );
+// msg_Dbg( p_demux, "| | | + 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( p_demux, "| | | + 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( p_demux, "| | | + Track Codec Info URL=%s", tk->psz_codec_download_url );
+// }
+// else if( EbmlId( *l ) == KaxCodecDecodeAll::ClassInfos.GlobalId )
+// {
+// KaxCodecDecodeAll &cdall = *(KaxCodecDecodeAll*)l;
+
+// msg_Dbg( p_demux, "| | | + Track Codec Decode All=%u <== UNUSED", uint8( cdall ) );
+// }
+// else if( EbmlId( *l ) == KaxTrackOverlay::ClassInfos.GlobalId )
+// {
+// KaxTrackOverlay &tovr = *(KaxTrackOverlay*)l;
+
+// msg_Dbg( p_demux, "| | | + Track Overlay=%u <== UNUSED", uint32( tovr ) );
+// }
+ else if( MKV_IS_ID( l, KaxTrackVideo ) )
+ {
+ EbmlMaster *tkv = static_cast<EbmlMaster*>(l);
+ unsigned int j;
+
+ msg_Dbg( p_demux, "| | | + Track Video" );
+ tk->f_fps = 0.0;
+
+ for( j = 0; j < tkv->ListSize(); j++ )
+ {
+ EbmlElement *l = (*tkv)[j];
+// if( EbmlId( *el4 ) == KaxVideoFlagInterlaced::ClassInfos.GlobalId )
+// {
+// KaxVideoFlagInterlaced &fint = *(KaxVideoFlagInterlaced*)el4;
+
+// msg_Dbg( p_demux, "| | | | + Track Video Interlaced=%u", uint8( fint ) );
+// }
+// else if( EbmlId( *el4 ) == KaxVideoStereoMode::ClassInfos.GlobalId )
+// {
+// KaxVideoStereoMode &stereo = *(KaxVideoStereoMode*)el4;
+
+// msg_Dbg( p_demux, "| | | | + 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( p_demux, "| | | | + width=%d", uint16( vwidth ) );
+ }
+ else if( MKV_IS_ID( l, KaxVideoPixelHeight ) )
+ {
+ KaxVideoPixelWidth &vheight = *(KaxVideoPixelWidth*)l;
+
+ tk->fmt.video.i_height = uint16( vheight );
+ msg_Dbg( p_demux, "| | | | + height=%d", uint16( vheight ) );
+ }
+ else if( MKV_IS_ID( l, KaxVideoDisplayWidth ) )
+ {
+ KaxVideoDisplayWidth &vwidth = *(KaxVideoDisplayWidth*)l;
+
+ tk->fmt.video.i_visible_width = uint16( vwidth );
+ msg_Dbg( p_demux, "| | | | + display width=%d", uint16( vwidth ) );
+ }
+ else if( MKV_IS_ID( l, KaxVideoDisplayHeight ) )
+ {
+ KaxVideoDisplayWidth &vheight = *(KaxVideoDisplayWidth*)l;
+
+ tk->fmt.video.i_visible_height = uint16( vheight );
+ msg_Dbg( p_demux, "| | | | + display height=%d", uint16( vheight ) );
+ }
+ else if( MKV_IS_ID( l, KaxVideoFrameRate ) )
+ {
+ KaxVideoFrameRate &vfps = *(KaxVideoFrameRate*)l;
+
+ tk->f_fps = float( vfps );
+ msg_Dbg( p_demux, " | | | + fps=%f", float( vfps ) );
+ }
+// else if( EbmlId( *l ) == KaxVideoDisplayUnit::ClassInfos.GlobalId )
+// {
+// KaxVideoDisplayUnit &vdmode = *(KaxVideoDisplayUnit*)l;
+
+// msg_Dbg( p_demux, "| | | | + 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( p_demux, " | | | + Track Video Aspect Ratio Type=%u", uint8( ratio ) );
+// }
+// else if( EbmlId( *l ) == KaxVideoGamma::ClassInfos.GlobalId )
+// {
+// KaxVideoGamma &gamma = *(KaxVideoGamma*)l;
+
+// msg_Dbg( p_demux, " | | | + fps=%f", float( gamma ) );
+// }
+ else
+ {
+ msg_Dbg( p_demux, "| | | | + Unknown (%s)", typeid(*l).name() );
+ }
+ }
+ }
+ else if( MKV_IS_ID( l, KaxTrackAudio ) )
+ {
+ EbmlMaster *tka = static_cast<EbmlMaster*>(l);
+ unsigned int j;
+
+ msg_Dbg( p_demux, "| | | + Track Audio" );
+
+ for( j = 0; j < tka->ListSize(); j++ )
+ {
+ EbmlElement *l = (*tka)[j];
+
+ if( MKV_IS_ID( l, KaxAudioSamplingFreq ) )
+ {
+ KaxAudioSamplingFreq &afreq = *(KaxAudioSamplingFreq*)l;
+
+ tk->fmt.audio.i_rate = (int)float( afreq );
+ msg_Dbg( p_demux, "| | | | + afreq=%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( p_demux, "| | | | + achan=%u", uint8( achan ) );
+ }
+ else if( MKV_IS_ID( l, KaxAudioBitDepth ) )
+ {
+ KaxAudioBitDepth &abits = *(KaxAudioBitDepth*)l;
+
+ tk->fmt.audio.i_bitspersample = uint8( abits );
+ msg_Dbg( p_demux, "| | | | + abits=%u", uint8( abits ) );
+ }
+ else
+ {
+ msg_Dbg( p_demux, "| | | | + Unknown (%s)", typeid(*l).name() );
+ }
+ }
+ }
+ else
+ {
+ msg_Dbg( p_demux, "| | | + Unknown (%s)",
+ typeid(*l).name() );
+ }
+ }
+}
+
+static void ParseTracks( demux_t *p_demux, EbmlElement *tracks )
+{
+ demux_sys_t *p_sys = p_demux->p_sys;
+ EbmlElement *el;
+ EbmlMaster *m;
+ unsigned int i;
+ int i_upper_level = 0;
+
+ msg_Dbg( p_demux, "| + Tracks" );
+
+ /* Master elements */
+ m = static_cast<EbmlMaster *>(tracks);
+ m->Read( *p_sys->es, tracks->Generic().Context, i_upper_level, el, true );
+
+ for( i = 0; i < m->ListSize(); i++ )
+ {
+ EbmlElement *l = (*m)[i];
+
+ if( MKV_IS_ID( l, KaxTrackEntry ) )
+ {
+ ParseTrackEntry( p_demux, static_cast<EbmlMaster *>(l) );
+ }
+ else
+ {
+ msg_Dbg( p_demux, "| | + Unknown (%s)", typeid(*l).name() );
+ }
+ }
+}
+
+/*****************************************************************************
+ * ParseInfo:
+ *****************************************************************************/
+static void ParseInfo( demux_t *p_demux, EbmlElement *info )
+{
+ demux_sys_t *p_sys = p_demux->p_sys;
+ EbmlElement *el;
+ EbmlMaster *m;
+ unsigned int i;
+ int i_upper_level = 0;
+
+ msg_Dbg( p_demux, "| + Information" );
+
+ /* Master elements */
+ m = static_cast<EbmlMaster *>(info);
+ m->Read( *p_sys->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 ) )
+ {
+ KaxSegmentUID &uid = *(KaxSegmentUID*)l;
+
+ msg_Dbg( p_demux, "| | + UID=%d", uint32(uid) );
+ }
+ else if( MKV_IS_ID( l, KaxTimecodeScale ) )
+ {
+ KaxTimecodeScale &tcs = *(KaxTimecodeScale*)l;
+
+ p_sys->i_timescale = uint64(tcs);
+
+ msg_Dbg( p_demux, "| | + TimecodeScale="I64Fd,
+ p_sys->i_timescale );
+ }
+ else if( MKV_IS_ID( l, KaxDuration ) )
+ {
+ KaxDuration &dur = *(KaxDuration*)l;
+
+ p_sys->f_duration = float(dur);
+
+ msg_Dbg( p_demux, "| | + Duration=%f",
+ p_sys->f_duration );
+ }
+ else if( MKV_IS_ID( l, KaxMuxingApp ) )
+ {
+ KaxMuxingApp &mapp = *(KaxMuxingApp*)l;
+
+ p_sys->psz_muxing_application = UTF8ToStr( UTFstring( mapp ) );
+
+ msg_Dbg( p_demux, "| | + Muxing Application=%s",
+ p_sys->psz_muxing_application );
+ }
+ else if( MKV_IS_ID( l, KaxWritingApp ) )
+ {
+ KaxWritingApp &wapp = *(KaxWritingApp*)l;
+
+ p_sys->psz_writing_application = UTF8ToStr( UTFstring( wapp ) );
+
+ msg_Dbg( p_demux, "| | + Writing Application=%s",
+ p_sys->psz_writing_application );
+ }
+ else if( MKV_IS_ID( l, KaxSegmentFilename ) )
+ {
+ KaxSegmentFilename &sfn = *(KaxSegmentFilename*)l;
+
+ p_sys->psz_segment_filename = UTF8ToStr( UTFstring( sfn ) );
+
+ msg_Dbg( p_demux, "| | + Segment Filename=%s",
+ p_sys->psz_segment_filename );
+ }
+ else if( MKV_IS_ID( l, KaxTitle ) )
+ {
+ KaxTitle &title = *(KaxTitle*)l;
+
+ p_sys->psz_title = UTF8ToStr( UTFstring( title ) );
+
+ msg_Dbg( p_demux, "| | + Title=%s", p_sys->psz_title );
+ }
+#if defined( HAVE_GMTIME_R ) && !defined( SYS_DARWIN )
+ 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';
+ p_sys->psz_date_utc = strdup( buffer );
+ msg_Dbg( p_demux, "| | + Date=%s", p_sys->psz_date_utc );
+ }
+ }
+#endif
+ else
+ {
+ msg_Dbg( p_demux, "| | + Unknown (%s)", typeid(*l).name() );
+ }
+ }
+
+ p_sys->f_duration = p_sys->f_duration * p_sys->i_timescale / 1000000.0;
+}
+
+
+/*****************************************************************************
+ * ParseChapterAtom
+ *****************************************************************************/
+static void ParseChapterAtom( demux_t *p_demux, int i_level, EbmlMaster *ca )
+{
+ demux_sys_t *p_sys = p_demux->p_sys;
+ unsigned int i;
+ seekpoint_t *sk;
+
+ if( p_sys->title == NULL )
+ {
+ p_sys->title = vlc_input_title_New();
+ }
+ sk = vlc_seekpoint_New();
+
+ msg_Dbg( p_demux, "| | | + ChapterAtom (level=%d)", i_level );
+ for( i = 0; i < ca->ListSize(); i++ )
+ {
+ EbmlElement *l = (*ca)[i];
+
+ if( MKV_IS_ID( l, KaxChapterUID ) )
+ {
+ KaxChapterUID &uid = *(KaxChapterUID*)l;
+ uint32_t i_uid = uint32( uid );
+ msg_Dbg( p_demux, "| | | | + ChapterUID: 0x%x", i_uid );
+ }
+ else if( MKV_IS_ID( l, KaxChapterTimeStart ) )
+ {
+ KaxChapterTimeStart &start =*(KaxChapterTimeStart*)l;
+ sk->i_time_offset = uint64( start ) / I64C(1000);
+
+ msg_Dbg( p_demux, "| | | | + ChapterTimeStart: %lld", sk->i_time_offset );
+ }
+ else if( MKV_IS_ID( l, KaxChapterTimeEnd ) )
+ {
+ KaxChapterTimeEnd &end =*(KaxChapterTimeEnd*)l;
+ int64_t i_end = uint64( end );
+
+ msg_Dbg( p_demux, "| | | | + ChapterTimeEnd: %lld", i_end );
+ }
+ else if( MKV_IS_ID( l, KaxChapterDisplay ) )
+ {
+ EbmlMaster *cd = static_cast<EbmlMaster *>(l);
+ unsigned int j;
+
+ msg_Dbg( p_demux, "| | | | + ChapterDisplay" );
+ for( j = 0; j < cd->ListSize(); j++ )
+ {
+ EbmlElement *l= (*cd)[j];
+
+ if( MKV_IS_ID( l, KaxChapterString ) )
+ {
+ KaxChapterString &name =*(KaxChapterString*)l;
+ char *psz = UTF8ToStr( UTFstring( name ) );
+ sk->psz_name = strdup( psz );
+ msg_Dbg( p_demux, "| | | | | + ChapterString '%s'", psz );
+ }
+ else if( MKV_IS_ID( l, KaxChapterLanguage ) )
+ {
+ KaxChapterLanguage &lang =*(KaxChapterLanguage*)l;
+ const char *psz = string( lang ).c_str();
+
+ msg_Dbg( p_demux, "| | | | | + ChapterLanguage '%s'", psz );
+ }
+ else if( MKV_IS_ID( l, KaxChapterCountry ) )
+ {
+ KaxChapterCountry &ct =*(KaxChapterCountry*)l;
+ const char *psz = string( ct ).c_str();
+
+ msg_Dbg( p_demux, "| | | | | + ChapterCountry '%s'", psz );
+ }
+ }
+ }
+ else if( MKV_IS_ID( l, KaxChapterAtom ) )
+ {
+ ParseChapterAtom( p_demux, i_level+1, static_cast<EbmlMaster *>(l) );
+ }
+ }
+ // A start time of '0' is ok. A missing ChapterTime element is ok, too, because '0' is its default value.
+ p_sys->title->i_seekpoint++;
+ p_sys->title->seekpoint = (seekpoint_t**)realloc( p_sys->title->seekpoint, p_sys->title->i_seekpoint * sizeof( seekpoint_t* ) );
+ p_sys->title->seekpoint[p_sys->title->i_seekpoint-1] = sk;
+}
+
+/*****************************************************************************
+ * ParseChapters:
+ *****************************************************************************/
+static void ParseChapters( demux_t *p_demux, EbmlElement *chapters )
+{
+ demux_sys_t *p_sys = p_demux->p_sys;
+ EbmlElement *el;
+ EbmlMaster *m;
+ unsigned int i;
+ int i_upper_level = 0;
+
+
+ /* Master elements */
+ m = static_cast<EbmlMaster *>(chapters);
+ m->Read( *p_sys->es, chapters->Generic().Context, i_upper_level, el, true );
+
+ for( i = 0; i < m->ListSize(); i++ )
+ {
+ EbmlElement *l = (*m)[i];
+
+ if( MKV_IS_ID( l, KaxEditionEntry ) )
+ {
+ EbmlMaster *E = static_cast<EbmlMaster *>(l );
+ unsigned int j;
+ msg_Dbg( p_demux, "| | + EditionEntry" );
+ for( j = 0; j < E->ListSize(); j++ )
+ {
+ EbmlElement *l = (*E)[j];
+
+ if( MKV_IS_ID( l, KaxChapterAtom ) )
+ {
+ ParseChapterAtom( p_demux, 0, static_cast<EbmlMaster *>(l) );
+ }
+ else
+ {
+ msg_Dbg( p_demux, "| | | + Unknown (%s)", typeid(*l).name() );
+ }
+ }
+ }
+ else
+ {
+ msg_Dbg( p_demux, "| | + Unknown (%s)", typeid(*l).name() );
+ }
+ }
+}
+
+/*****************************************************************************
+ * InformationCreate:
+ *****************************************************************************/
+static void InformationCreate( demux_t *p_demux )
+{
+ demux_sys_t *p_sys = p_demux->p_sys;
+ int i_track;
+
+ p_sys->meta = vlc_meta_New();