]> git.sesse.net Git - vlc/blob - modules/demux/mkv/matroska_segment_parse.cpp
matroska: Using forward declaration for EbmlParser
[vlc] / modules / demux / mkv / matroska_segment_parse.cpp
1 /*****************************************************************************
2  * mkv.cpp : matroska demuxer
3  *****************************************************************************
4  * Copyright (C) 2003-2010 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
8  *          Steve Lhomme <steve.lhomme@free.fr>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23  *****************************************************************************/
24
25 #include "matroska_segment.hpp"
26
27 #include "chapters.hpp"
28
29 #include "demux.hpp"
30
31 #include "Ebml_parser.hpp"
32
33 /*****************************************************************************
34  * Some functions to manipulate memory
35  *****************************************************************************/
36 static inline char * ToUTF8( const UTFstring &u )
37 {
38     return strdup( u.GetUTF8().c_str() );
39 }
40
41 /*****************************************************************************
42  * ParseSeekHead:
43  *****************************************************************************/
44 void matroska_segment_c::ParseSeekHead( KaxSeekHead *seekhead )
45 {
46     EbmlParser  *ep;
47     EbmlElement *l;
48     bool b_seekable;
49
50     i_seekhead_count++;
51
52     stream_Control( sys.demuxer.s, STREAM_CAN_SEEK, &b_seekable );
53     if( !b_seekable )
54         return;
55
56     ep = new EbmlParser( &es, seekhead, &sys.demuxer );
57
58     while( ( l = ep->Get() ) != NULL )
59     {
60         if( MKV_IS_ID( l, KaxSeek ) )
61         {
62             EbmlId id = EBML_ID(EbmlVoid);
63             int64_t i_pos = -1;
64
65 #ifdef MKV_DEBUG
66             msg_Dbg( &sys.demuxer, "|   |   + Seek" );
67 #endif
68             ep->Down();
69             while( ( l = ep->Get() ) != NULL )
70             {
71                 if( MKV_IS_ID( l, KaxSeekID ) )
72                 {
73                     KaxSeekID &sid = *(KaxSeekID*)l;
74                     sid.ReadData( es.I_O() );
75                     id = EbmlId( sid.GetBuffer(), sid.GetSize() );
76                 }
77                 else if( MKV_IS_ID( l, KaxSeekPosition ) )
78                 {
79                     KaxSeekPosition &spos = *(KaxSeekPosition*)l;
80                     spos.ReadData( es.I_O() );
81                     i_pos = (int64_t)segment->GetGlobalPosition( uint64( spos ) );
82                 }
83                 else
84                 {
85                     /* Many mkvmerge files hit this case. It seems to be a broken SeekHead */
86                     msg_Dbg( &sys.demuxer, "|   |   + Unknown (%s)", typeid(*l).name()  );
87                 }
88             }
89             ep->Up();
90
91             if( i_pos >= 0 )
92             {
93                 if( id == EBML_ID(KaxCues) )
94                 {
95                     msg_Dbg( &sys.demuxer, "|   - cues at %"PRId64, i_pos );
96                     LoadSeekHeadItem( EBML_INFO(KaxCues), i_pos );
97                 }
98                 else if( id == EBML_ID(KaxInfo) )
99                 {
100                     msg_Dbg( &sys.demuxer, "|   - info at %"PRId64, i_pos );
101                     LoadSeekHeadItem( EBML_INFO(KaxInfo), i_pos );
102                 }
103                 else if( id == EBML_ID(KaxChapters) )
104                 {
105                     msg_Dbg( &sys.demuxer, "|   - chapters at %"PRId64, i_pos );
106                     LoadSeekHeadItem( EBML_INFO(KaxChapters), i_pos );
107                 }
108                 else if( id == EBML_ID(KaxTags) )
109                 {
110                     msg_Dbg( &sys.demuxer, "|   - tags at %"PRId64, i_pos );
111                     LoadSeekHeadItem( EBML_INFO(KaxTags), i_pos );
112                 }
113                 else if( id == EBML_ID(KaxSeekHead) )
114                 {
115                     msg_Dbg( &sys.demuxer, "|   - chained seekhead at %"PRId64, i_pos );
116                     LoadSeekHeadItem( EBML_INFO(KaxSeekHead), i_pos );
117                 }
118                 else if( id == EBML_ID(KaxTracks) )
119                 {
120                     msg_Dbg( &sys.demuxer, "|   - tracks at %"PRId64, i_pos );
121                     LoadSeekHeadItem( EBML_INFO(KaxTracks), i_pos );
122                 }
123                 else if( id == EBML_ID(KaxAttachments) )
124                 {
125                     msg_Dbg( &sys.demuxer, "|   - attachments at %"PRId64, i_pos );
126                     LoadSeekHeadItem( EBML_INFO(KaxAttachments), i_pos );
127                 }
128 #ifdef MKV_DEBUG
129                 else
130                     msg_Dbg( &sys.demuxer, "|   - unknown seekhead reference at %"PRId64, i_pos );
131 #endif
132             }
133         }
134         else
135             msg_Dbg( &sys.demuxer, "|   |   + ParseSeekHead Unknown (%s)", typeid(*l).name() );
136     }
137     delete ep;
138 }
139
140
141 /**
142  * Helper function to print the mkv parse tree
143  */
144 static void MkvTree( demux_t & demuxer, int i_level, const char *psz_format, ... )
145 {
146     va_list args;
147     if( i_level > 9 )
148     {
149         msg_Err( &demuxer, "MKV tree is too deep" );
150         return;
151     }
152     va_start( args, psz_format );
153     static const char psz_foo[] = "|   |   |   |   |   |   |   |   |   |";
154     char *psz_foo2 = (char*)malloc( i_level * 4 + 3 + strlen( psz_format ) );
155     strncpy( psz_foo2, psz_foo, 4 * i_level );
156     psz_foo2[ 4 * i_level ] = '+';
157     psz_foo2[ 4 * i_level + 1 ] = ' ';
158     strcpy( &psz_foo2[ 4 * i_level + 2 ], psz_format );
159     msg_GenericVa( &demuxer,VLC_MSG_DBG, "mkv", psz_foo2, args );
160     free( psz_foo2 );
161     va_end( args );
162 }
163
164
165 /*****************************************************************************
166  * ParseTrackEntry:
167  *****************************************************************************/
168 void matroska_segment_c::ParseTrackEntry( KaxTrackEntry *m )
169 {
170     bool bSupported = true;
171
172     /* Init the track */
173     mkv_track_t *tk = new mkv_track_t();
174     memset( tk, 0, sizeof( mkv_track_t ) );
175
176     es_format_Init( &tk->fmt, UNKNOWN_ES, 0 );
177     tk->fmt.psz_language       = strdup("English");
178     tk->fmt.psz_description    = NULL;
179
180     tk->b_default              = true;
181     tk->b_enabled              = true;
182     tk->b_silent               = false;
183     tk->i_number               = tracks.size() - 1;
184     tk->i_extra_data           = 0;
185     tk->p_extra_data           = NULL;
186     tk->psz_codec              = NULL;
187     tk->b_dts_only             = false;
188     tk->i_default_duration     = 0;
189     tk->f_timecodescale        = 1.0;
190
191     tk->b_inited               = false;
192     tk->i_data_init            = 0;
193     tk->p_data_init            = NULL;
194
195     tk->psz_codec_name         = NULL;
196     tk->psz_codec_settings     = NULL;
197     tk->psz_codec_info_url     = NULL;
198     tk->psz_codec_download_url = NULL;
199
200     tk->i_compression_type     = MATROSKA_COMPRESSION_NONE;
201     tk->p_compression_data     = NULL;
202
203     msg_Dbg( &sys.demuxer, "|   |   + Track Entry" );
204
205     for( size_t i = 0; i < m->ListSize(); i++ )
206     {
207         EbmlElement *l = (*m)[i];
208
209         if( MKV_IS_ID( l, KaxTrackNumber ) )
210         {
211             KaxTrackNumber &tnum = *(KaxTrackNumber*)l;
212
213             tk->i_number = uint32( tnum );
214             msg_Dbg( &sys.demuxer, "|   |   |   + Track Number=%u", uint32( tnum ) );
215         }
216         else  if( MKV_IS_ID( l, KaxTrackUID ) )
217         {
218             KaxTrackUID &tuid = *(KaxTrackUID*)l;
219
220             msg_Dbg( &sys.demuxer, "|   |   |   + Track UID=%u",  uint32( tuid ) );
221         }
222         else  if( MKV_IS_ID( l, KaxTrackType ) )
223         {
224             const char *psz_type;
225             KaxTrackType &ttype = *(KaxTrackType*)l;
226
227             switch( uint8(ttype) )
228             {
229                 case track_audio:
230                     psz_type = "audio";
231                     tk->fmt.i_cat = AUDIO_ES;
232                     break;
233                 case track_video:
234                     psz_type = "video";
235                     tk->fmt.i_cat = VIDEO_ES;
236                     break;
237                 case track_subtitle:
238                     psz_type = "subtitle";
239                     tk->fmt.i_cat = SPU_ES;
240                     break;
241                 case track_buttons:
242                     psz_type = "buttons";
243                     tk->fmt.i_cat = SPU_ES;
244                     break;
245                 default:
246                     psz_type = "unknown";
247                     tk->fmt.i_cat = UNKNOWN_ES;
248                     break;
249             }
250
251             msg_Dbg( &sys.demuxer, "|   |   |   + Track Type=%s", psz_type );
252         }
253         else  if( MKV_IS_ID( l, KaxTrackFlagEnabled ) ) // UNUSED
254         {
255             KaxTrackFlagEnabled &fenb = *(KaxTrackFlagEnabled*)l;
256
257             // tk->b_enabled = uint32( fenb );
258             msg_Dbg( &sys.demuxer, "|   |   |   + Track Enabled=%u", uint32( fenb ) );
259         }
260         else  if( MKV_IS_ID( l, KaxTrackFlagDefault ) )
261         {
262             KaxTrackFlagDefault &fdef = *(KaxTrackFlagDefault*)l;
263
264             tk->b_default = uint32( fdef );
265             msg_Dbg( &sys.demuxer, "|   |   |   + Track Default=%u", uint32( fdef ) );
266         }
267         else  if( MKV_IS_ID( l, KaxTrackFlagForced ) ) // UNUSED
268         {
269             KaxTrackFlagForced &ffor = *(KaxTrackFlagForced*)l;
270
271             msg_Dbg( &sys.demuxer, "|   |   |   + Track Forced=%u", uint32( ffor ) );
272         }
273         else  if( MKV_IS_ID( l, KaxTrackFlagLacing ) ) // UNUSED
274         {
275             KaxTrackFlagLacing &lac = *(KaxTrackFlagLacing*)l;
276
277             msg_Dbg( &sys.demuxer, "|   |   |   + Track Lacing=%d", uint32( lac ) );
278         }
279         else  if( MKV_IS_ID( l, KaxTrackMinCache ) ) // UNUSED
280         {
281             KaxTrackMinCache &cmin = *(KaxTrackMinCache*)l;
282
283             msg_Dbg( &sys.demuxer, "|   |   |   + Track MinCache=%d", uint32( cmin ) );
284         }
285         else  if( MKV_IS_ID( l, KaxTrackMaxCache ) ) // UNUSED
286         {
287             KaxTrackMaxCache &cmax = *(KaxTrackMaxCache*)l;
288
289             msg_Dbg( &sys.demuxer, "|   |   |   + Track MaxCache=%d", uint32( cmax ) );
290         }
291         else  if( MKV_IS_ID( l, KaxTrackDefaultDuration ) )
292         {
293             KaxTrackDefaultDuration &defd = *(KaxTrackDefaultDuration*)l;
294
295             tk->i_default_duration = uint64(defd);
296             msg_Dbg( &sys.demuxer, "|   |   |   + Track Default Duration=%"PRId64, uint64(defd) );
297         }
298         else  if( MKV_IS_ID( l, KaxTrackTimecodeScale ) )
299         {
300             KaxTrackTimecodeScale &ttcs = *(KaxTrackTimecodeScale*)l;
301
302             tk->f_timecodescale = float( ttcs );
303             msg_Dbg( &sys.demuxer, "|   |   |   + Track TimeCodeScale=%f", tk->f_timecodescale );
304         }
305         else  if( MKV_IS_ID( l, KaxMaxBlockAdditionID ) ) // UNUSED
306         {
307             KaxMaxBlockAdditionID &mbl = *(KaxMaxBlockAdditionID*)l;
308
309             msg_Dbg( &sys.demuxer, "|   |   |   + Track Max BlockAdditionID=%d", uint32( mbl ) );
310         }
311         else if( MKV_IS_ID( l, KaxTrackName ) )
312         {
313             KaxTrackName &tname = *(KaxTrackName*)l;
314
315             tk->fmt.psz_description = ToUTF8( UTFstring( tname ) );
316             msg_Dbg( &sys.demuxer, "|   |   |   + Track Name=%s", tk->fmt.psz_description );
317         }
318         else  if( MKV_IS_ID( l, KaxTrackLanguage ) )
319         {
320             KaxTrackLanguage &lang = *(KaxTrackLanguage*)l;
321
322             free( tk->fmt.psz_language );
323             tk->fmt.psz_language = strdup( string( lang ).c_str() );
324             msg_Dbg( &sys.demuxer,
325                      "|   |   |   + Track Language=`%s'", tk->fmt.psz_language );
326         }
327         else  if( MKV_IS_ID( l, KaxCodecID ) )
328         {
329             KaxCodecID &codecid = *(KaxCodecID*)l;
330
331             tk->psz_codec = strdup( string( codecid ).c_str() );
332             msg_Dbg( &sys.demuxer, "|   |   |   + Track CodecId=%s", string( codecid ).c_str() );
333         }
334         else  if( MKV_IS_ID( l, KaxCodecPrivate ) )
335         {
336             KaxCodecPrivate &cpriv = *(KaxCodecPrivate*)l;
337
338             tk->i_extra_data = cpriv.GetSize();
339             if( tk->i_extra_data > 0 )
340             {
341                 tk->p_extra_data = (uint8_t*)malloc( tk->i_extra_data );
342                 memcpy( tk->p_extra_data, cpriv.GetBuffer(), tk->i_extra_data );
343             }
344             msg_Dbg( &sys.demuxer, "|   |   |   + Track CodecPrivate size=%"PRId64, cpriv.GetSize() );
345         }
346         else if( MKV_IS_ID( l, KaxCodecName ) )
347         {
348             KaxCodecName &cname = *(KaxCodecName*)l;
349
350             tk->psz_codec_name = ToUTF8( UTFstring( cname ) );
351             msg_Dbg( &sys.demuxer, "|   |   |   + Track Codec Name=%s", tk->psz_codec_name );
352         }
353         //AttachmentLink
354         else if( MKV_IS_ID( l, KaxCodecDecodeAll ) ) // UNUSED
355         {
356             KaxCodecDecodeAll &cdall = *(KaxCodecDecodeAll*)l;
357
358             msg_Dbg( &sys.demuxer, "|   |   |   + Track Codec Decode All=%u", uint8( cdall ) );
359         }
360         else if( MKV_IS_ID( l, KaxTrackOverlay ) ) // UNUSED
361         {
362             KaxTrackOverlay &tovr = *(KaxTrackOverlay*)l;
363
364             msg_Dbg( &sys.demuxer, "|   |   |   + Track Overlay=%u", uint32( tovr ) );
365         }
366         else if( MKV_IS_ID( l, KaxContentEncodings ) )
367         {
368             EbmlMaster *cencs = static_cast<EbmlMaster*>(l);
369             MkvTree( sys.demuxer, 3, "Content Encodings" );
370             if ( cencs->ListSize() > 1 )
371             {
372                 msg_Err( &sys.demuxer, "Multiple Compression method not supported" );
373                 bSupported = false;
374             }
375             for( size_t j = 0; j < cencs->ListSize(); j++ )
376             {
377                 EbmlElement *l2 = (*cencs)[j];
378                 if( MKV_IS_ID( l2, KaxContentEncoding ) )
379                 {
380                     MkvTree( sys.demuxer, 4, "Content Encoding" );
381                     EbmlMaster *cenc = static_cast<EbmlMaster*>(l2);
382                     for( size_t k = 0; k < cenc->ListSize(); k++ )
383                     {
384                         EbmlElement *l3 = (*cenc)[k];
385                         if( MKV_IS_ID( l3, KaxContentEncodingOrder ) )
386                         {
387                             KaxContentEncodingOrder &encord = *(KaxContentEncodingOrder*)l3;
388                             MkvTree( sys.demuxer, 5, "Order: %i", uint32( encord ) );
389                         }
390                         else if( MKV_IS_ID( l3, KaxContentEncodingScope ) )
391                         {
392                             KaxContentEncodingScope &encscope = *(KaxContentEncodingScope*)l3;
393                             MkvTree( sys.demuxer, 5, "Scope: %i", uint32( encscope ) );
394                         }
395                         else if( MKV_IS_ID( l3, KaxContentEncodingType ) )
396                         {
397                             KaxContentEncodingType &enctype = *(KaxContentEncodingType*)l3;
398                             MkvTree( sys.demuxer, 5, "Type: %i", uint32( enctype ) );
399                         }
400                         else if( MKV_IS_ID( l3, KaxContentCompression ) )
401                         {
402                             EbmlMaster *compr = static_cast<EbmlMaster*>(l3);
403                             MkvTree( sys.demuxer, 5, "Content Compression" );
404                             //Default compression type is 0 (Zlib)
405                             tk->i_compression_type = MATROSKA_COMPRESSION_ZLIB;
406                             for( size_t n = 0; n < compr->ListSize(); n++ )
407                             {
408                                 EbmlElement *l4 = (*compr)[n];
409                                 if( MKV_IS_ID( l4, KaxContentCompAlgo ) )
410                                 {
411                                     KaxContentCompAlgo &compalg = *(KaxContentCompAlgo*)l4;
412                                     MkvTree( sys.demuxer, 6, "Compression Algorithm: %i", uint32(compalg) );
413                                     tk->i_compression_type = uint32( compalg );
414                                     if ( ( tk->i_compression_type != MATROSKA_COMPRESSION_ZLIB ) &&
415                                          ( tk->i_compression_type != MATROSKA_COMPRESSION_HEADER ) )
416                                     {
417                                         msg_Err( &sys.demuxer, "Track Compression method %d not supported", tk->i_compression_type );
418                                         bSupported = false;
419                                     }
420                                 }
421                                 else if( MKV_IS_ID( l4, KaxContentCompSettings ) )
422                                 {
423                                     tk->p_compression_data = new KaxContentCompSettings( *(KaxContentCompSettings*)l4 );
424                                 }
425                                 else
426                                 {
427                                     MkvTree( sys.demuxer, 6, "Unknown (%s)", typeid(*l4).name() );
428                                 }
429                             }
430                         }
431                         // ContentEncryption Unsupported
432                         else
433                         {
434                             MkvTree( sys.demuxer, 5, "Unknown (%s)", typeid(*l3).name() );
435                         }
436                     }
437                 }
438                 else
439                 {
440                     MkvTree( sys.demuxer, 4, "Unknown (%s)", typeid(*l2).name() );
441                 }
442             }
443         }
444 //        else if( MKV_IS_ID( l, KaxCodecSettings) ) DEPRECATED by matroska
445 //        {
446 //            KaxCodecSettings &cset = *(KaxCodecSettings*)l;
447
448 //            tk->psz_codec_settings = ToUTF8( UTFstring( cset ) );
449 //            msg_Dbg( &sys.demuxer, "|   |   |   + Track Codec Settings=%s", tk->psz_codec_settings );
450 //        }
451 //        else if( MKV_IS_ID( l, KaxCodecInfoURL) ) DEPRECATED by matroska
452 //        {
453 //            KaxCodecInfoURL &ciurl = *(KaxCodecInfoURL*)l;
454
455 //            tk->psz_codec_info_url = strdup( string( ciurl ).c_str() );
456 //            msg_Dbg( &sys.demuxer, "|   |   |   + Track Codec Info URL=%s", tk->psz_codec_info_url );
457 //        }
458 //        else if( MKV_IS_ID( l, KaxCodecDownloadURL) ) DEPRECATED by matroska
459 //        {
460 //            KaxCodecDownloadURL &cdurl = *(KaxCodecDownloadURL*)l;
461
462 //            tk->psz_codec_download_url = strdup( string( cdurl ).c_str() );
463 //            msg_Dbg( &sys.demuxer, "|   |   |   + Track Codec Info URL=%s", tk->psz_codec_download_url );
464 //        }
465         else  if( MKV_IS_ID( l, KaxTrackVideo ) )
466         {
467             EbmlMaster *tkv = static_cast<EbmlMaster*>(l);
468             unsigned int i_crop_right = 0, i_crop_left = 0, i_crop_top = 0, i_crop_bottom = 0;
469             unsigned int i_display_unit = 0, i_display_width = 0, i_display_height = 0;
470
471             msg_Dbg( &sys.demuxer, "|   |   |   + Track Video" );
472             tk->f_fps = 0.0;
473
474             tk->fmt.video.i_frame_rate_base = (unsigned int)(tk->i_default_duration / 1000);
475             tk->fmt.video.i_frame_rate = 1000000;
476
477             for( unsigned int j = 0; j < tkv->ListSize(); j++ )
478             {
479                 EbmlElement *l = (*tkv)[j];
480                 if( MKV_IS_ID( l, KaxVideoFlagInterlaced ) ) // UNUSED
481                 {
482                     KaxVideoFlagInterlaced &fint = *(KaxVideoFlagInterlaced*)l;
483
484                     msg_Dbg( &sys.demuxer, "|   |   |   |   + Track Video Interlaced=%u", uint8( fint ) );
485                 }
486                 else if( MKV_IS_ID( l, KaxVideoStereoMode ) ) // UNUSED
487                 {
488                     KaxVideoStereoMode &stereo = *(KaxVideoStereoMode*)l;
489
490                     msg_Dbg( &sys.demuxer, "|   |   |   |   + Track Video Stereo Mode=%u", uint8( stereo ) );
491                 }
492                 else if( MKV_IS_ID( l, KaxVideoPixelWidth ) )
493                 {
494                     KaxVideoPixelWidth &vwidth = *(KaxVideoPixelWidth*)l;
495
496                     tk->fmt.video.i_width += uint16( vwidth );
497                     msg_Dbg( &sys.demuxer, "|   |   |   |   + width=%d", uint16( vwidth ) );
498                 }
499                 else if( MKV_IS_ID( l, KaxVideoPixelHeight ) )
500                 {
501                     KaxVideoPixelWidth &vheight = *(KaxVideoPixelWidth*)l;
502
503                     tk->fmt.video.i_height += uint16( vheight );
504                     msg_Dbg( &sys.demuxer, "|   |   |   |   + height=%d", uint16( vheight ) );
505                 }
506                 else if( MKV_IS_ID( l, KaxVideoDisplayWidth ) )
507                 {
508                     KaxVideoDisplayWidth &vwidth = *(KaxVideoDisplayWidth*)l;
509
510                     i_display_width = uint16( vwidth );
511                     msg_Dbg( &sys.demuxer, "|   |   |   |   + display width=%d", uint16( vwidth ) );
512                 }
513                 else if( MKV_IS_ID( l, KaxVideoDisplayHeight ) )
514                 {
515                     KaxVideoDisplayWidth &vheight = *(KaxVideoDisplayWidth*)l;
516
517                     i_display_height = uint16( vheight );
518                     msg_Dbg( &sys.demuxer, "|   |   |   |   + display height=%d", uint16( vheight ) );
519                 }
520                 else if( MKV_IS_ID( l, KaxVideoPixelCropBottom ) )
521                 {
522                     KaxVideoPixelCropBottom &cropval = *(KaxVideoPixelCropBottom*)l;
523
524                     i_crop_bottom = uint16( cropval );
525                     msg_Dbg( &sys.demuxer, "|   |   |   |   + crop pixel bottom=%d", uint16( cropval ) );
526                 }
527                 else if( MKV_IS_ID( l, KaxVideoPixelCropTop ) )
528                 {
529                     KaxVideoPixelCropTop &cropval = *(KaxVideoPixelCropTop*)l;
530
531                     i_crop_top = uint16( cropval );
532                     msg_Dbg( &sys.demuxer, "|   |   |   |   + crop pixel top=%d", uint16( cropval ) );
533                 }
534                 else if( MKV_IS_ID( l, KaxVideoPixelCropRight ) )
535                 {
536                     KaxVideoPixelCropRight &cropval = *(KaxVideoPixelCropRight*)l;
537
538                     i_crop_right = uint16( cropval );
539                     msg_Dbg( &sys.demuxer, "|   |   |   |   + crop pixel right=%d", uint16( cropval ) );
540                 }
541                 else if( MKV_IS_ID( l, KaxVideoPixelCropLeft ) )
542                 {
543                     KaxVideoPixelCropLeft &cropval = *(KaxVideoPixelCropLeft*)l;
544
545                     i_crop_left = uint16( cropval );
546                     msg_Dbg( &sys.demuxer, "|   |   |   |   + crop pixel left=%d", uint16( cropval ) );
547                 }
548                 else if( MKV_IS_ID( l, KaxVideoDisplayUnit ) )
549                 {
550                     KaxVideoDisplayUnit &vdmode = *(KaxVideoDisplayUnit*)l;
551
552                     i_display_unit = uint8( vdmode );
553                     msg_Dbg( &sys.demuxer, "|   |   |   |   + Track Video Display Unit=%s",
554                              i_display_unit == 0 ? "pixels" : ( i_display_unit == 1 ? "centimeters": "inches" ) );
555                 }
556                 else if( MKV_IS_ID( l, KaxVideoAspectRatio ) ) // UNUSED
557                 {
558                     KaxVideoAspectRatio &ratio = *(KaxVideoAspectRatio*)l;
559
560                     msg_Dbg( &sys.demuxer, "   |   |   |   + Track Video Aspect Ratio Type=%u", uint8( ratio ) );
561                 }
562                 // ColourSpace UNUSED
563                 else if( MKV_IS_ID( l, KaxVideoFrameRate ) )
564                 {
565                     KaxVideoFrameRate &vfps = *(KaxVideoFrameRate*)l;
566
567                     tk->f_fps = float( vfps );
568                     msg_Dbg( &sys.demuxer, "   |   |   |   + fps=%f", float( vfps ) );
569                 }
570 //                else if( MKV_IS_ID( l, KaxVideoGamma) ) //DEPRECATED by Matroska
571 //                {
572 //                    KaxVideoGamma &gamma = *(KaxVideoGamma*)l;
573
574 //                    msg_Dbg( &sys.demuxer, "   |   |   |   + gamma=%f", float( gamma ) );
575 //                }
576                 else
577                 {
578                     msg_Dbg( &sys.demuxer, "|   |   |   |   + Unknown (%s)", typeid(*l).name() );
579                 }
580             }
581             if( i_display_height && i_display_width )
582             {
583                 tk->fmt.video.i_sar_num = i_display_width  * tk->fmt.video.i_height;
584                 tk->fmt.video.i_sar_den = i_display_height * tk->fmt.video.i_width;
585             }
586             if( i_crop_left || i_crop_right || i_crop_top || i_crop_bottom )
587             {
588                 tk->fmt.video.i_visible_width   = tk->fmt.video.i_width;
589                 tk->fmt.video.i_visible_height  = tk->fmt.video.i_height;
590                 tk->fmt.video.i_x_offset        = i_crop_left;
591                 tk->fmt.video.i_y_offset        = i_crop_top;
592                 tk->fmt.video.i_visible_width  -= i_crop_left + i_crop_right;
593                 tk->fmt.video.i_visible_height -= i_crop_top + i_crop_bottom;
594             }
595             /* FIXME: i_display_* allows you to not only set DAR, but also a zoom factor.
596                we do not support this atm */
597         }
598         else  if( MKV_IS_ID( l, KaxTrackAudio ) )
599         {
600             EbmlMaster *tka = static_cast<EbmlMaster*>(l);
601
602             msg_Dbg( &sys.demuxer, "|   |   |   + Track Audio" );
603
604             for( unsigned int j = 0; j < tka->ListSize(); j++ )
605             {
606                 EbmlElement *l = (*tka)[j];
607
608                 if( MKV_IS_ID( l, KaxAudioSamplingFreq ) )
609                 {
610                     KaxAudioSamplingFreq &afreq = *(KaxAudioSamplingFreq*)l;
611
612                     tk->i_original_rate = tk->fmt.audio.i_rate = (int)float( afreq );
613                     msg_Dbg( &sys.demuxer, "|   |   |   |   + afreq=%d", tk->fmt.audio.i_rate );
614                 }
615                 else if( MKV_IS_ID( l, KaxAudioOutputSamplingFreq ) )
616                 {
617                     KaxAudioOutputSamplingFreq &afreq = *(KaxAudioOutputSamplingFreq*)l;
618
619                     tk->fmt.audio.i_rate = (int)float( afreq );
620                     msg_Dbg( &sys.demuxer, "|   |   |   |   + aoutfreq=%d", tk->fmt.audio.i_rate );
621                 }
622                 else if( MKV_IS_ID( l, KaxAudioChannels ) )
623                 {
624                     KaxAudioChannels &achan = *(KaxAudioChannels*)l;
625
626                     tk->fmt.audio.i_channels = uint8( achan );
627                     msg_Dbg( &sys.demuxer, "|   |   |   |   + achan=%u", uint8( achan ) );
628                 }
629                 else if( MKV_IS_ID( l, KaxAudioBitDepth ) )
630                 {
631                     KaxAudioBitDepth &abits = *(KaxAudioBitDepth*)l;
632
633                     tk->fmt.audio.i_bitspersample = uint8( abits );
634                     msg_Dbg( &sys.demuxer, "|   |   |   |   + abits=%u", uint8( abits ) );
635                 }
636                 else
637                 {
638                     msg_Dbg( &sys.demuxer, "|   |   |   |   + Unknown (%s)", typeid(*l).name() );
639                 }
640             }
641         }
642         else
643         {
644             msg_Dbg( &sys.demuxer, "|   |   |   + Unknown (%s)",
645                      typeid(*l).name() );
646         }
647     }
648
649     if ( bSupported )
650     {
651         tracks.push_back( tk );
652     }
653     else
654     {
655         msg_Err( &sys.demuxer, "Track Entry %d not supported", tk->i_number );
656         delete tk;
657     }
658 }
659
660 /*****************************************************************************
661  * ParseTracks:
662  *****************************************************************************/
663 void matroska_segment_c::ParseTracks( KaxTracks *tracks )
664 {
665     EbmlElement *el;
666     int i_upper_level = 0;
667
668     /* Master elements */
669     tracks->Read( es, EBML_CONTEXT(tracks), i_upper_level, el, true );
670
671     for( size_t i = 0; i < tracks->ListSize(); i++ )
672     {
673         EbmlElement *l = (*tracks)[i];
674
675         if( MKV_IS_ID( l, KaxTrackEntry ) )
676         {
677             ParseTrackEntry( static_cast<KaxTrackEntry *>(l) );
678         }
679         else
680         {
681             msg_Dbg( &sys.demuxer, "|   |   + Unknown (%s)", typeid(*l).name() );
682         }
683     }
684 }
685
686 /*****************************************************************************
687  * ParseInfo:
688  *****************************************************************************/
689 void matroska_segment_c::ParseInfo( KaxInfo *info )
690 {
691     EbmlElement *el;
692     EbmlMaster  *m;
693     int i_upper_level = 0;
694
695     /* Master elements */
696     m = static_cast<EbmlMaster *>(info);
697     m->Read( es, EBML_CONTEXT(info), i_upper_level, el, true );
698
699     for( size_t i = 0; i < m->ListSize(); i++ )
700     {
701         EbmlElement *l = (*m)[i];
702
703         if( MKV_IS_ID( l, KaxSegmentUID ) )
704         {
705             if ( p_segment_uid == NULL )
706                 p_segment_uid = new KaxSegmentUID(*static_cast<KaxSegmentUID*>(l));
707
708             msg_Dbg( &sys.demuxer, "|   |   + UID=%d", *(uint32*)p_segment_uid->GetBuffer() );
709         }
710         else if( MKV_IS_ID( l, KaxPrevUID ) )
711         {
712             if ( p_prev_segment_uid == NULL )
713                 p_prev_segment_uid = new KaxPrevUID(*static_cast<KaxPrevUID*>(l));
714
715             msg_Dbg( &sys.demuxer, "|   |   + PrevUID=%d", *(uint32*)p_prev_segment_uid->GetBuffer() );
716         }
717         else if( MKV_IS_ID( l, KaxNextUID ) )
718         {
719             if ( p_next_segment_uid == NULL )
720                 p_next_segment_uid = new KaxNextUID(*static_cast<KaxNextUID*>(l));
721
722             msg_Dbg( &sys.demuxer, "|   |   + NextUID=%d", *(uint32*)p_next_segment_uid->GetBuffer() );
723         }
724         else if( MKV_IS_ID( l, KaxTimecodeScale ) )
725         {
726             KaxTimecodeScale &tcs = *(KaxTimecodeScale*)l;
727
728             i_timescale = uint64(tcs);
729
730             msg_Dbg( &sys.demuxer, "|   |   + TimecodeScale=%"PRId64,
731                      i_timescale );
732         }
733         else if( MKV_IS_ID( l, KaxDuration ) )
734         {
735             KaxDuration &dur = *(KaxDuration*)l;
736
737             i_duration = mtime_t( double( dur ) );
738
739             msg_Dbg( &sys.demuxer, "|   |   + Duration=%"PRId64,
740                      i_duration );
741         }
742         else if( MKV_IS_ID( l, KaxMuxingApp ) )
743         {
744             KaxMuxingApp &mapp = *(KaxMuxingApp*)l;
745
746             psz_muxing_application = ToUTF8( UTFstring( mapp ) );
747
748             msg_Dbg( &sys.demuxer, "|   |   + Muxing Application=%s",
749                      psz_muxing_application );
750         }
751         else if( MKV_IS_ID( l, KaxWritingApp ) )
752         {
753             KaxWritingApp &wapp = *(KaxWritingApp*)l;
754
755             psz_writing_application = ToUTF8( UTFstring( wapp ) );
756
757             msg_Dbg( &sys.demuxer, "|   |   + Writing Application=%s",
758                      psz_writing_application );
759         }
760         else if( MKV_IS_ID( l, KaxSegmentFilename ) )
761         {
762             KaxSegmentFilename &sfn = *(KaxSegmentFilename*)l;
763
764             psz_segment_filename = ToUTF8( UTFstring( sfn ) );
765
766             msg_Dbg( &sys.demuxer, "|   |   + Segment Filename=%s",
767                      psz_segment_filename );
768         }
769         else if( MKV_IS_ID( l, KaxTitle ) )
770         {
771             KaxTitle &title = *(KaxTitle*)l;
772
773             psz_title = ToUTF8( UTFstring( title ) );
774
775             msg_Dbg( &sys.demuxer, "|   |   + Title=%s", psz_title );
776         }
777         else if( MKV_IS_ID( l, KaxSegmentFamily ) )
778         {
779             KaxSegmentFamily *uid = static_cast<KaxSegmentFamily*>(l);
780
781             families.push_back( new KaxSegmentFamily(*uid) );
782
783             msg_Dbg( &sys.demuxer, "|   |   + family=%d", *(uint32*)uid->GetBuffer() );
784         }
785         else if( MKV_IS_ID( l, KaxDateUTC ) )
786         {
787             KaxDateUTC &date = *(KaxDateUTC*)l;
788             time_t i_date;
789             struct tm tmres;
790             char   buffer[25];
791
792             i_date = date.GetEpochDate();
793             if( gmtime_r( &i_date, &tmres ) &&
794                 strftime( buffer, sizeof(buffer), "%a %b %d %H:%M:%S %Y",
795                           &tmres ) )
796             {
797                 psz_date_utc = strdup( buffer );
798                 msg_Dbg( &sys.demuxer, "|   |   + Date=%s", buffer );
799             }
800         }
801         else if( MKV_IS_ID( l, KaxChapterTranslate ) )
802         {
803             KaxChapterTranslate *p_trans = static_cast<KaxChapterTranslate*>( l );
804             chapter_translation_c *p_translate = new chapter_translation_c();
805
806             p_trans->Read( es, EBML_CONTEXT(p_trans), i_upper_level, el, true );
807             for( size_t j = 0; j < p_trans->ListSize(); j++ )
808             {
809                 EbmlElement *l = (*p_trans)[j];
810
811                 if( MKV_IS_ID( l, KaxChapterTranslateEditionUID ) )
812                 {
813                     p_translate->editions.push_back( uint64( *static_cast<KaxChapterTranslateEditionUID*>( l ) ) );
814                 }
815                 else if( MKV_IS_ID( l, KaxChapterTranslateCodec ) )
816                 {
817                     p_translate->codec_id = uint32( *static_cast<KaxChapterTranslateCodec*>( l ) );
818                 }
819                 else if( MKV_IS_ID( l, KaxChapterTranslateID ) )
820                 {
821                     p_translate->p_translated = new KaxChapterTranslateID( *static_cast<KaxChapterTranslateID*>( l ) );
822                 }
823             }
824
825             translations.push_back( p_translate );
826         }
827         else
828         {
829             msg_Dbg( &sys.demuxer, "|   |   + Unknown (%s)", typeid(*l).name() );
830         }
831     }
832
833     double f_dur = double(i_duration) * double(i_timescale) / 1000000.0;
834     i_duration = mtime_t(f_dur);
835 }
836
837
838 /*****************************************************************************
839  * ParseChapterAtom
840  *****************************************************************************/
841 void matroska_segment_c::ParseChapterAtom( int i_level, KaxChapterAtom *ca, chapter_item_c & chapters )
842 {
843     msg_Dbg( &sys.demuxer, "|   |   |   + ChapterAtom (level=%d)", i_level );
844     for( size_t i = 0; i < ca->ListSize(); i++ )
845     {
846         EbmlElement *l = (*ca)[i];
847
848         if( MKV_IS_ID( l, KaxChapterUID ) )
849         {
850             chapters.i_uid = uint64_t(*(KaxChapterUID*)l);
851             msg_Dbg( &sys.demuxer, "|   |   |   |   + ChapterUID: %"PRIu64"", chapters.i_uid );
852         }
853         else if( MKV_IS_ID( l, KaxChapterFlagHidden ) )
854         {
855             KaxChapterFlagHidden &flag =*(KaxChapterFlagHidden*)l;
856             chapters.b_display_seekpoint = uint8( flag ) == 0;
857
858             msg_Dbg( &sys.demuxer, "|   |   |   |   + ChapterFlagHidden: %s", chapters.b_display_seekpoint ? "no":"yes" );
859         }
860         else if( MKV_IS_ID( l, KaxChapterSegmentUID ) )
861         {
862             chapters.p_segment_uid = new KaxChapterSegmentUID( *static_cast<KaxChapterSegmentUID*>(l) );
863             msg_Dbg( &sys.demuxer, "|   |   |   |   + ChapterSegmentUID= %u", *(uint32*)chapters.p_segment_uid->GetBuffer() );
864         }
865         else if( MKV_IS_ID( l, KaxChapterSegmentEditionUID ) )
866         {
867             chapters.p_segment_edition_uid = new KaxChapterSegmentEditionUID( *static_cast<KaxChapterSegmentEditionUID*>(l) );
868             msg_Dbg( &sys.demuxer, "|   |   |   |   + ChapterSegmentEditionUID= %u",
869 #if LIBMATROSKA_VERSION < 0x010300
870             *(uint32*)chapters.p_segment_edition_uid->GetBuffer()
871 #else
872             *(uint32*)chapters.p_segment_edition_uid
873 #endif
874             );
875         }
876         else if( MKV_IS_ID( l, KaxChapterTimeStart ) )
877         {
878             KaxChapterTimeStart &start =*(KaxChapterTimeStart*)l;
879             chapters.i_start_time = uint64( start ) / INT64_C(1000);
880
881             msg_Dbg( &sys.demuxer, "|   |   |   |   + ChapterTimeStart: %"PRId64"", chapters.i_start_time );
882         }
883         else if( MKV_IS_ID( l, KaxChapterTimeEnd ) )
884         {
885             KaxChapterTimeEnd &end =*(KaxChapterTimeEnd*)l;
886             chapters.i_end_time = uint64( end ) / INT64_C(1000);
887
888             msg_Dbg( &sys.demuxer, "|   |   |   |   + ChapterTimeEnd: %"PRId64"", chapters.i_end_time );
889         }
890         else if( MKV_IS_ID( l, KaxChapterDisplay ) )
891         {
892             EbmlMaster *cd = static_cast<EbmlMaster *>(l);
893
894             msg_Dbg( &sys.demuxer, "|   |   |   |   + ChapterDisplay" );
895             for( size_t j = 0; j < cd->ListSize(); j++ )
896             {
897                 EbmlElement *l= (*cd)[j];
898
899                 if( MKV_IS_ID( l, KaxChapterString ) )
900                 {
901                     KaxChapterString &name =*(KaxChapterString*)l;
902                     for ( int k = 0; k < i_level; k++)
903                         chapters.psz_name += '+';
904                     chapters.psz_name += ' ';
905                     char *psz_tmp_utf8 = ToUTF8( UTFstring( name ) );
906                     chapters.psz_name += psz_tmp_utf8;
907                     chapters.b_user_display = true;
908
909                     msg_Dbg( &sys.demuxer, "|   |   |   |   |    + ChapterString '%s'", psz_tmp_utf8 );
910                     free( psz_tmp_utf8 );
911                 }
912                 else if( MKV_IS_ID( l, KaxChapterLanguage ) )
913                 {
914                     KaxChapterLanguage &lang =*(KaxChapterLanguage*)l;
915                     const char *psz = string( lang ).c_str();
916
917                     msg_Dbg( &sys.demuxer, "|   |   |   |   |    + ChapterLanguage '%s'", psz );
918                 }
919                 else if( MKV_IS_ID( l, KaxChapterCountry ) )
920                 {
921                     KaxChapterCountry &ct =*(KaxChapterCountry*)l;
922                     const char *psz = string( ct ).c_str();
923
924                     msg_Dbg( &sys.demuxer, "|   |   |   |   |    + ChapterCountry '%s'", psz );
925                 }
926             }
927         }
928         else if( MKV_IS_ID( l, KaxChapterProcess ) )
929         {
930             msg_Dbg( &sys.demuxer, "|   |   |   |   + ChapterProcess" );
931
932             KaxChapterProcess *cp = static_cast<KaxChapterProcess *>(l);
933             chapter_codec_cmds_c *p_ccodec = NULL;
934
935             for( size_t j = 0; j < cp->ListSize(); j++ )
936             {
937                 EbmlElement *k= (*cp)[j];
938
939                 if( MKV_IS_ID( k, KaxChapterProcessCodecID ) )
940                 {
941                     KaxChapterProcessCodecID *p_codec_id = static_cast<KaxChapterProcessCodecID*>( k );
942                     if ( uint32(*p_codec_id) == 0 )
943                         p_ccodec = new matroska_script_codec_c( sys );
944                     else if ( uint32(*p_codec_id) == 1 )
945                         p_ccodec = new dvd_chapter_codec_c( sys );
946                     break;
947                 }
948             }
949
950             if ( p_ccodec != NULL )
951             {
952                 for( size_t j = 0; j < cp->ListSize(); j++ )
953                 {
954                     EbmlElement *k= (*cp)[j];
955
956                     if( MKV_IS_ID( k, KaxChapterProcessPrivate ) )
957                     {
958                         KaxChapterProcessPrivate * p_private = static_cast<KaxChapterProcessPrivate*>( k );
959                         p_ccodec->SetPrivate( *p_private );
960                     }
961                     else if( MKV_IS_ID( k, KaxChapterProcessCommand ) )
962                     {
963                         p_ccodec->AddCommand( *static_cast<KaxChapterProcessCommand*>( k ) );
964                     }
965                 }
966                 chapters.codecs.push_back( p_ccodec );
967             }
968         }
969         else if( MKV_IS_ID( l, KaxChapterAtom ) )
970         {
971             chapter_item_c *new_sub_chapter = new chapter_item_c();
972             ParseChapterAtom( i_level+1, static_cast<KaxChapterAtom *>(l), *new_sub_chapter );
973             new_sub_chapter->p_parent = &chapters;
974             chapters.sub_chapters.push_back( new_sub_chapter );
975         }
976     }
977 }
978
979 /*****************************************************************************
980  * ParseAttachments:
981  *****************************************************************************/
982 void matroska_segment_c::ParseAttachments( KaxAttachments *attachments )
983 {
984     EbmlElement *el;
985     int i_upper_level = 0;
986
987     attachments->Read( es, EBML_CONTEXT(attachments), i_upper_level, el, true );
988
989     KaxAttached *attachedFile = FindChild<KaxAttached>( *attachments );
990
991     while( attachedFile && ( attachedFile->GetSize() > 0 ) )
992     {
993         KaxFileData  &img_data     = GetChild<KaxFileData>( *attachedFile );
994         attachment_c *new_attachment = new attachment_c( ToUTF8( UTFstring( GetChild<KaxFileName>( *attachedFile ) ) ),
995                                                         GetChild<KaxMimeType>( *attachedFile ),
996                                                         img_data.GetSize() );
997
998         if( new_attachment->init() )
999         {
1000              memcpy( new_attachment->p_data, img_data.GetBuffer(), img_data.GetSize() );
1001              sys.stored_attachments.push_back( new_attachment );
1002         }
1003         else
1004         {
1005             delete new_attachment;
1006         }
1007
1008         attachedFile = &GetNextChild<KaxAttached>( *attachments, *attachedFile );
1009     }
1010 }
1011
1012 /*****************************************************************************
1013  * ParseChapters:
1014  *****************************************************************************/
1015 void matroska_segment_c::ParseChapters( KaxChapters *chapters )
1016 {
1017     EbmlElement *el;
1018     int i_upper_level = 0;
1019
1020     /* Master elements */
1021     chapters->Read( es, EBML_CONTEXT(chapters), i_upper_level, el, true );
1022
1023     for( size_t i = 0; i < chapters->ListSize(); i++ )
1024     {
1025         EbmlElement *l = (*chapters)[i];
1026
1027         if( MKV_IS_ID( l, KaxEditionEntry ) )
1028         {
1029             chapter_edition_c *p_edition = new chapter_edition_c();
1030
1031             EbmlMaster *E = static_cast<EbmlMaster *>(l );
1032             msg_Dbg( &sys.demuxer, "|   |   + EditionEntry" );
1033             for( size_t j = 0; j < E->ListSize(); j++ )
1034             {
1035                 EbmlElement *l = (*E)[j];
1036
1037                 if( MKV_IS_ID( l, KaxChapterAtom ) )
1038                 {
1039                     chapter_item_c *new_sub_chapter = new chapter_item_c();
1040                     ParseChapterAtom( 0, static_cast<KaxChapterAtom *>(l), *new_sub_chapter );
1041                     p_edition->sub_chapters.push_back( new_sub_chapter );
1042                 }
1043                 else if( MKV_IS_ID( l, KaxEditionUID ) )
1044                 {
1045                     p_edition->i_uid = uint64(*static_cast<KaxEditionUID *>( l ));
1046                 }
1047                 else if( MKV_IS_ID( l, KaxEditionFlagOrdered ) )
1048                 {
1049                     p_edition->b_ordered = var_InheritBool( &sys.demuxer, "mkv-use-ordered-chapters" ) ? (uint8(*static_cast<KaxEditionFlagOrdered *>( l )) != 0) : 0;
1050                 }
1051                 else if( MKV_IS_ID( l, KaxEditionFlagDefault ) )
1052                 {
1053                     if (uint8(*static_cast<KaxEditionFlagDefault *>( l )) != 0)
1054                         i_default_edition = stored_editions.size();
1055                 }
1056                 else if( MKV_IS_ID( l, KaxEditionFlagHidden ) )
1057                 {
1058                     // FIXME to implement
1059                 }
1060                 else
1061                 {
1062                     msg_Dbg( &sys.demuxer, "|   |   |   + Unknown (%s)", typeid(*l).name() );
1063                 }
1064             }
1065             stored_editions.push_back( p_edition );
1066         }
1067         else
1068         {
1069             msg_Dbg( &sys.demuxer, "|   |   + Unknown (%s)", typeid(*l).name() );
1070         }
1071     }
1072 }
1073
1074 void matroska_segment_c::ParseCluster( )
1075 {
1076     EbmlElement *el;
1077     EbmlMaster  *m;
1078     int i_upper_level = 0;
1079
1080     /* Master elements */
1081     m = static_cast<EbmlMaster *>( cluster );
1082     m->Read( es, EBML_CONTEXT(cluster), i_upper_level, el, true );
1083
1084     for( unsigned int i = 0; i < m->ListSize(); i++ )
1085     {
1086         EbmlElement *l = (*m)[i];
1087
1088         if( MKV_IS_ID( l, KaxClusterTimecode ) )
1089         {
1090             KaxClusterTimecode &ctc = *(KaxClusterTimecode*)l;
1091
1092             cluster->InitTimecode( uint64( ctc ), i_timescale );
1093             break;
1094         }
1095     }
1096
1097     i_start_time = cluster->GlobalTimecode() / 1000;
1098 }
1099