]> git.sesse.net Git - vlc/blob - modules/demux/mkv.cpp
mkv.cpp: better timecode sent by the demuxer (doesn't seem right with native MPEG4.2)
[vlc] / modules / demux / mkv.cpp
1 /*****************************************************************************
2  * mkv.cpp : matroska demuxer
3  *****************************************************************************
4  * Copyright (C) 2003-2004 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., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
23  *****************************************************************************/
24
25 /*****************************************************************************
26  * Preamble
27  *****************************************************************************/
28 #include <stdlib.h>                                      /* malloc(), free() */
29
30 #include <vlc/vlc.h>
31
32 #ifdef HAVE_TIME_H
33 #   include <time.h>                                               /* time() */
34 #endif
35
36 #include <vlc/input.h>
37
38 #include <codecs.h>                        /* BITMAPINFOHEADER, WAVEFORMATEX */
39 #include "iso_lang.h"
40 #include "vlc_meta.h"
41
42 #include <iostream>
43 #include <cassert>
44 #include <typeinfo>
45 #include <string>
46 #include <vector>
47 #include <algorithm>
48
49 #ifdef HAVE_DIRENT_H
50 #   include <dirent.h>
51 #endif
52
53 /* libebml and matroska */
54 #include "ebml/EbmlHead.h"
55 #include "ebml/EbmlSubHead.h"
56 #include "ebml/EbmlStream.h"
57 #include "ebml/EbmlContexts.h"
58 #include "ebml/EbmlVoid.h"
59 #include "ebml/EbmlVersion.h"
60 #include "ebml/StdIOCallback.h"
61
62 #include "matroska/KaxAttachments.h"
63 #include "matroska/KaxBlock.h"
64 #include "matroska/KaxBlockData.h"
65 #include "matroska/KaxChapters.h"
66 #include "matroska/KaxCluster.h"
67 #include "matroska/KaxClusterData.h"
68 #include "matroska/KaxContexts.h"
69 #include "matroska/KaxCues.h"
70 #include "matroska/KaxCuesData.h"
71 #include "matroska/KaxInfo.h"
72 #include "matroska/KaxInfoData.h"
73 #include "matroska/KaxSeekHead.h"
74 #include "matroska/KaxSegment.h"
75 #include "matroska/KaxTag.h"
76 #include "matroska/KaxTags.h"
77 #include "matroska/KaxTagMulti.h"
78 #include "matroska/KaxTracks.h"
79 #include "matroska/KaxTrackAudio.h"
80 #include "matroska/KaxTrackVideo.h"
81 #include "matroska/KaxTrackEntryData.h"
82 #include "matroska/KaxContentEncoding.h"
83 #include "matroska/KaxVersion.h"
84
85 #include "ebml/StdIOCallback.h"
86
87 #if LIBMATROSKA_VERSION < 0x000706
88 START_LIBMATROSKA_NAMESPACE
89 extern const EbmlSemanticContext MATROSKA_DLL_API KaxMatroska_Context;
90 END_LIBMATROSKA_NAMESPACE
91 #endif
92
93 #include "vlc_keys.h"
94
95 extern "C" {
96    #include "mp4/libmp4.h"
97 }
98 #ifdef HAVE_ZLIB_H
99 #   include <zlib.h>
100 #endif
101
102 #define MATROSKA_COMPRESSION_NONE 0
103 #define MATROSKA_COMPRESSION_ZLIB 1
104
105 #define MKVD_TIMECODESCALE 1000000
106
107 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
108 #undef ATTRIBUTE_PACKED
109 #undef PRAGMA_PACK_BEGIN 
110 #undef PRAGMA_PACK_END
111
112 #if defined(__GNUC__)
113 #if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 95)
114 #define ATTRIBUTE_PACKED __attribute__ ((packed))
115 #define PRAGMA_PACK 0
116 #endif
117 #endif
118
119 #if !defined(ATTRIBUTE_PACKED)
120 #define ATTRIBUTE_PACKED
121 #define PRAGMA_PACK 1
122 #endif
123
124 #if PRAGMA_PACK
125 #pragma pack(1)
126 #endif
127
128 /*************************************
129 *  taken from libdvdnav / libdvdread
130 **************************************/
131
132 /**
133  * DVD Time Information.
134  */
135 typedef struct {
136   uint8_t hour;
137   uint8_t minute;
138   uint8_t second;
139   uint8_t frame_u; /* The two high bits are the frame rate. */
140 } ATTRIBUTE_PACKED dvd_time_t;
141
142 /**
143  * User Operations.
144  */
145 typedef struct {
146 #ifdef WORDS_BIGENDIAN
147   unsigned char zero                           : 7; /* 25-31 */
148   unsigned char video_pres_mode_change         : 1; /* 24 */
149   
150   unsigned char karaoke_audio_pres_mode_change : 1; /* 23 */
151   unsigned char angle_change                   : 1;
152   unsigned char subpic_stream_change           : 1;
153   unsigned char audio_stream_change            : 1;
154   unsigned char pause_on                       : 1;
155   unsigned char still_off                      : 1;
156   unsigned char button_select_or_activate      : 1;
157   unsigned char resume                         : 1; /* 16 */
158   
159   unsigned char chapter_menu_call              : 1; /* 15 */
160   unsigned char angle_menu_call                : 1;
161   unsigned char audio_menu_call                : 1;
162   unsigned char subpic_menu_call               : 1;
163   unsigned char root_menu_call                 : 1;
164   unsigned char title_menu_call                : 1;
165   unsigned char backward_scan                  : 1;
166   unsigned char forward_scan                   : 1; /* 8 */
167   
168   unsigned char next_pg_search                 : 1; /* 7 */
169   unsigned char prev_or_top_pg_search          : 1;
170   unsigned char time_or_chapter_search         : 1;
171   unsigned char go_up                          : 1;
172   unsigned char stop                           : 1;
173   unsigned char title_play                     : 1;
174   unsigned char chapter_search_or_play         : 1;
175   unsigned char title_or_time_play             : 1; /* 0 */
176 #else
177   unsigned char video_pres_mode_change         : 1; /* 24 */
178   unsigned char zero                           : 7; /* 25-31 */
179   
180   unsigned char resume                         : 1; /* 16 */
181   unsigned char button_select_or_activate      : 1;
182   unsigned char still_off                      : 1;
183   unsigned char pause_on                       : 1;
184   unsigned char audio_stream_change            : 1;
185   unsigned char subpic_stream_change           : 1;
186   unsigned char angle_change                   : 1;
187   unsigned char karaoke_audio_pres_mode_change : 1; /* 23 */
188   
189   unsigned char forward_scan                   : 1; /* 8 */
190   unsigned char backward_scan                  : 1;
191   unsigned char title_menu_call                : 1;
192   unsigned char root_menu_call                 : 1;
193   unsigned char subpic_menu_call               : 1;
194   unsigned char audio_menu_call                : 1;
195   unsigned char angle_menu_call                : 1;
196   unsigned char chapter_menu_call              : 1; /* 15 */
197   
198   unsigned char title_or_time_play             : 1; /* 0 */
199   unsigned char chapter_search_or_play         : 1;
200   unsigned char title_play                     : 1;
201   unsigned char stop                           : 1;
202   unsigned char go_up                          : 1;
203   unsigned char time_or_chapter_search         : 1;
204   unsigned char prev_or_top_pg_search          : 1;
205   unsigned char next_pg_search                 : 1; /* 7 */
206 #endif
207 } ATTRIBUTE_PACKED user_ops_t;
208
209 /**
210  * Type to store per-command data.
211  */
212 typedef struct {
213   uint8_t bytes[8];
214 } ATTRIBUTE_PACKED vm_cmd_t;
215 #define COMMAND_DATA_SIZE 8
216
217 /**
218  * PCI General Information 
219  */
220 typedef struct {
221   uint32_t nv_pck_lbn;      /**< sector address of this nav pack */
222   uint16_t vobu_cat;        /**< 'category' of vobu */
223   uint16_t zero1;           /**< reserved */
224   user_ops_t vobu_uop_ctl;  /**< UOP of vobu */
225   uint32_t vobu_s_ptm;      /**< start presentation time of vobu */
226   uint32_t vobu_e_ptm;      /**< end presentation time of vobu */
227   uint32_t vobu_se_e_ptm;   /**< end ptm of sequence end in vobu */
228   dvd_time_t e_eltm;        /**< Cell elapsed time */
229   char vobu_isrc[32];
230 } ATTRIBUTE_PACKED pci_gi_t;
231
232 /**
233  * Non Seamless Angle Information
234  */
235 typedef struct {
236   uint32_t nsml_agl_dsta[9];  /**< address of destination vobu in AGL_C#n */
237 } ATTRIBUTE_PACKED nsml_agli_t;
238
239 /** 
240  * Highlight General Information 
241  *
242  * For btngrX_dsp_ty the bits have the following meaning:
243  * 000b: normal 4/3 only buttons
244  * XX1b: wide (16/9) buttons
245  * X1Xb: letterbox buttons
246  * 1XXb: pan&scan buttons
247  */
248 typedef struct {
249   uint16_t hli_ss; /**< status, only low 2 bits 0: no buttons, 1: different 2: equal 3: eual except for button cmds */
250   uint32_t hli_s_ptm;              /**< start ptm of hli */
251   uint32_t hli_e_ptm;              /**< end ptm of hli */
252   uint32_t btn_se_e_ptm;           /**< end ptm of button select */
253 #ifdef WORDS_BIGENDIAN
254   unsigned char zero1 : 2;          /**< reserved */
255   unsigned char btngr_ns : 2;       /**< number of button groups 1, 2 or 3 with 36/18/12 buttons */
256   unsigned char zero2 : 1;          /**< reserved */
257   unsigned char btngr1_dsp_ty : 3;  /**< display type of subpic stream for button group 1 */
258   unsigned char zero3 : 1;          /**< reserved */
259   unsigned char btngr2_dsp_ty : 3;  /**< display type of subpic stream for button group 2 */
260   unsigned char zero4 : 1;          /**< reserved */
261   unsigned char btngr3_dsp_ty : 3;  /**< display type of subpic stream for button group 3 */
262 #else
263   unsigned char btngr1_dsp_ty : 3;
264   unsigned char zero2 : 1;
265   unsigned char btngr_ns : 2;
266   unsigned char zero1 : 2;
267   unsigned char btngr3_dsp_ty : 3;
268   unsigned char zero4 : 1;
269   unsigned char btngr2_dsp_ty : 3;
270   unsigned char zero3 : 1;
271 #endif
272   uint8_t btn_ofn;     /**< button offset number range 0-255 */
273   uint8_t btn_ns;      /**< number of valid buttons  <= 36/18/12 (low 6 bits) */  
274   uint8_t nsl_btn_ns;  /**< number of buttons selectable by U_BTNNi (low 6 bits)   nsl_btn_ns <= btn_ns */
275   uint8_t zero5;       /**< reserved */
276   uint8_t fosl_btnn;   /**< forcedly selected button  (low 6 bits) */
277   uint8_t foac_btnn;   /**< forcedly activated button (low 6 bits) */
278 } ATTRIBUTE_PACKED hl_gi_t;
279
280
281 /** 
282  * Button Color Information Table 
283  * Each entry beeing a 32bit word that contains the color indexs and alpha
284  * values to use.  They are all represented by 4 bit number and stored
285  * like this [Ci3, Ci2, Ci1, Ci0, A3, A2, A1, A0].   The actual palette
286  * that the indexes reference is in the PGC.
287  * @TODO split the uint32_t into a struct
288  */
289 typedef struct {
290   uint32_t btn_coli[3][2];  /**< [button color number-1][select:0/action:1] */
291 } ATTRIBUTE_PACKED btn_colit_t;
292
293 /** 
294  * Button Information
295  *
296  * NOTE: I've had to change the structure from the disk layout to get
297  * the packing to work with Sun's Forte C compiler.
298  * The 4 and 7 bytes are 'rotated' was: ABC DEF GHIJ  is: ABCG DEFH IJ
299  */
300 typedef struct {
301 #ifdef WORDS_BIGENDIAN
302   uint32        btn_coln         : 2;  /**< button color number */
303   uint32        x_start          : 10; /**< x start offset within the overlay */
304   uint32        zero1            : 2;  /**< reserved */
305   uint32        x_end            : 10; /**< x end offset within the overlay */
306
307   uint32        zero3            : 2;  /**< reserved */
308   uint32        up               : 6;  /**< button index when pressing up */
309
310   uint32        auto_action_mode : 2;  /**< 0: no, 1: activated if selected */
311   uint32        y_start          : 10; /**< y start offset within the overlay */
312   uint32        zero2            : 2;  /**< reserved */
313   uint32        y_end            : 10; /**< y end offset within the overlay */
314
315   uint32        zero4            : 2;  /**< reserved */
316   uint32        down             : 6;  /**< button index when pressing down */
317   unsigned char zero5            : 2;  /**< reserved */
318   unsigned char left             : 6;  /**< button index when pressing left */
319   unsigned char zero6            : 2;  /**< reserved */
320   unsigned char right            : 6;  /**< button index when pressing right */
321 #else
322   uint32        x_end            : 10;
323   uint32        zero1            : 2;
324   uint32        x_start          : 10;
325   uint32        btn_coln         : 2;
326
327   uint32        up               : 6;
328   uint32        zero3            : 2;
329
330   uint32        y_end            : 10;
331   uint32        zero2            : 2;
332   uint32        y_start          : 10;
333   uint32        auto_action_mode : 2;
334
335   uint32        down             : 6;
336   uint32        zero4            : 2;
337   unsigned char left             : 6;
338   unsigned char zero5            : 2;
339   unsigned char right            : 6;
340   unsigned char zero6            : 2;
341 #endif
342   vm_cmd_t cmd;
343 } ATTRIBUTE_PACKED btni_t;
344
345 /**
346  * Highlight Information 
347  */
348 typedef struct {
349   hl_gi_t     hl_gi;
350   btn_colit_t btn_colit;
351   btni_t      btnit[36];
352 } ATTRIBUTE_PACKED hli_t;
353
354 /**
355  * PCI packet
356  */
357 typedef struct {
358   pci_gi_t    pci_gi;
359   nsml_agli_t nsml_agli;
360   hli_t       hli;
361   uint8_t     zero1[189];
362 } ATTRIBUTE_PACKED pci_t;
363
364
365 #if PRAGMA_PACK
366 #pragma pack()
367 #endif
368 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
369
370
371 /**
372  * What's between a directory and a filename?
373  */
374 #if defined( WIN32 )
375     #define DIRECTORY_SEPARATOR '\\'
376 #else
377     #define DIRECTORY_SEPARATOR '/'
378 #endif
379
380 using namespace LIBMATROSKA_NAMESPACE;
381 using namespace std;
382
383 /*****************************************************************************
384  * Module descriptor
385  *****************************************************************************/
386 static int  Open ( vlc_object_t * );
387 static void Close( vlc_object_t * );
388
389 vlc_module_begin();
390     set_shortname( "Matroska" );
391     set_description( _("Matroska stream demuxer" ) );
392     set_capability( "demux2", 50 );
393     set_callbacks( Open, Close );
394     set_category( CAT_INPUT );
395     set_subcategory( SUBCAT_INPUT_DEMUX );
396
397     add_bool( "mkv-use-ordered-chapters", 1, NULL,
398             N_("Ordered chapters"),
399             N_("Play ordered chapters as specified in the segment."), VLC_TRUE );
400
401     add_bool( "mkv-use-chapter-codec", 1, NULL,
402             N_("Chapter codecs"),
403             N_("Use chapter codecs found in the segment."), VLC_TRUE );
404
405     add_bool( "mkv-seek-percent", 0, NULL,
406             N_("Seek based on percent not time"),
407             N_("Seek based on percent not time."), VLC_TRUE );
408
409     add_bool( "mkv-use-dummy", 0, NULL,
410             N_("Dummy Elements"),
411             N_("Read and discard unknown EBML elements (not good for broken files)."), VLC_TRUE );
412
413     add_shortcut( "mka" );
414     add_shortcut( "mkv" );
415 vlc_module_end();
416
417 /*****************************************************************************
418  * Local prototypes
419  *****************************************************************************/
420 #ifdef HAVE_ZLIB_H
421 block_t *block_zlib_decompress( vlc_object_t *p_this, block_t *p_in_block ) {
422     int result, dstsize, n;
423     unsigned char *dst;
424     block_t *p_block;
425     z_stream d_stream;
426
427     d_stream.zalloc = (alloc_func)0;
428     d_stream.zfree = (free_func)0;
429     d_stream.opaque = (voidpf)0;
430     result = inflateInit(&d_stream);
431     if( result != Z_OK )
432     {
433         msg_Dbg( p_this, "inflateInit() failed. Result: %d", result );
434         return NULL;
435     }
436
437     d_stream.next_in = (Bytef *)p_in_block->p_buffer;
438     d_stream.avail_in = p_in_block->i_buffer;
439     n = 0;
440     p_block = block_New( p_this, 0 );
441     dst = NULL;
442     do
443     {
444         n++;
445         p_block = block_Realloc( p_block, 0, n * 1000 );
446         dst = (unsigned char *)p_block->p_buffer;
447         d_stream.next_out = (Bytef *)&dst[(n - 1) * 1000];
448         d_stream.avail_out = 1000;
449         result = inflate(&d_stream, Z_NO_FLUSH);
450         if( ( result != Z_OK ) && ( result != Z_STREAM_END ) )
451         {
452             msg_Dbg( p_this, "Zlib decompression failed. Result: %d", result );
453             return NULL;
454         }
455     }
456     while( ( d_stream.avail_out == 0 ) && ( d_stream.avail_in != 0 ) &&
457            ( result != Z_STREAM_END ) );
458
459     dstsize = d_stream.total_out;
460     inflateEnd( &d_stream );
461
462     p_block = block_Realloc( p_block, 0, dstsize );
463     p_block->i_buffer = dstsize;
464     block_Release( p_in_block );
465
466     return p_block;
467 }
468 #endif
469
470 /**
471  * Helper function to print the mkv parse tree
472  */
473 static void MkvTree( demux_t & demuxer, int i_level, char *psz_format, ... )
474 {
475     va_list args;
476     if( i_level > 9 )
477     {
478         msg_Err( &demuxer, "too deep tree" );
479         return;
480     }
481     va_start( args, psz_format );
482     static char *psz_foo = "|   |   |   |   |   |   |   |   |   |";
483     char *psz_foo2 = (char*)malloc( ( i_level * 4 + 3 + strlen( psz_format ) ) * sizeof(char) );
484     strncpy( psz_foo2, psz_foo, 4 * i_level );
485     psz_foo2[ 4 * i_level ] = '+';
486     psz_foo2[ 4 * i_level + 1 ] = ' ';
487     strcpy( &psz_foo2[ 4 * i_level + 2 ], psz_format );
488     __msg_GenericVa( VLC_OBJECT(&demuxer), VLC_MSG_DBG, "mkv", psz_foo2, args );
489     free( psz_foo2 );
490     va_end( args );
491 }
492     
493 /*****************************************************************************
494  * Stream managment
495  *****************************************************************************/
496 class vlc_stream_io_callback: public IOCallback
497 {
498   private:
499     stream_t       *s;
500     vlc_bool_t     mb_eof;
501     vlc_bool_t     b_owner;
502
503   public:
504     vlc_stream_io_callback( stream_t *, vlc_bool_t );
505
506     virtual ~vlc_stream_io_callback()
507     {
508         if( b_owner )
509             stream_Delete( s );
510     }
511
512     virtual uint32   read            ( void *p_buffer, size_t i_size);
513     virtual void     setFilePointer  ( int64_t i_offset, seek_mode mode = seek_beginning );
514     virtual size_t   write           ( const void *p_buffer, size_t i_size);
515     virtual uint64   getFilePointer  ( void );
516     virtual void     close           ( void );
517 };
518
519 /*****************************************************************************
520  * Ebml Stream parser
521  *****************************************************************************/
522 class EbmlParser
523 {
524   public:
525     EbmlParser( EbmlStream *es, EbmlElement *el_start, demux_t *p_demux );
526     virtual ~EbmlParser( void );
527
528     void Up( void );
529     void Down( void );
530     void Reset( demux_t *p_demux );
531     EbmlElement *Get( void );
532     void        Keep( void );
533     EbmlElement *UnGet( uint64 i_block_pos, uint64 i_cluster_pos );
534
535     int GetLevel( void );
536
537   private:
538     EbmlStream  *m_es;
539     int         mi_level;
540     EbmlElement *m_el[10];
541     int64_t      mi_remain_size[10];
542
543     EbmlElement *m_got;
544
545     int         mi_user_level;
546     vlc_bool_t  mb_keep;
547     vlc_bool_t  mb_dummy;
548 };
549
550
551 /*****************************************************************************
552  * Some functions to manipulate memory
553  *****************************************************************************/
554 #define GetFOURCC( p )  __GetFOURCC( (uint8_t*)p )
555 static vlc_fourcc_t __GetFOURCC( uint8_t *p )
556 {
557     return VLC_FOURCC( p[0], p[1], p[2], p[3] );
558 }
559
560 /*****************************************************************************
561  * definitions of structures and functions used by this plugins
562  *****************************************************************************/
563 typedef struct
564 {
565     vlc_bool_t   b_default;
566     vlc_bool_t   b_enabled;
567     unsigned int i_number;
568
569     int          i_extra_data;
570     uint8_t      *p_extra_data;
571
572     char         *psz_codec;
573
574     uint64_t     i_default_duration;
575     float        f_timecodescale;
576     mtime_t      i_last_dts;
577
578     /* video */
579     es_format_t fmt;
580     float       f_fps;
581     es_out_id_t *p_es;
582
583     vlc_bool_t      b_inited;
584     /* data to be send first */
585     int             i_data_init;
586     uint8_t         *p_data_init;
587
588     /* hack : it's for seek */
589     vlc_bool_t      b_search_keyframe;
590     vlc_bool_t      b_silent;
591
592     /* informative */
593     char         *psz_codec_name;
594     char         *psz_codec_settings;
595     char         *psz_codec_info_url;
596     char         *psz_codec_download_url;
597     
598     /* encryption/compression */
599     int           i_compression_type;
600
601 } mkv_track_t;
602
603 typedef struct
604 {
605     int     i_track;
606     int     i_block_number;
607
608     int64_t i_position;
609     int64_t i_time;
610
611     vlc_bool_t b_key;
612 } mkv_index_t;
613
614 class demux_sys_t;
615
616 const binary MATROSKA_DVD_LEVEL_SS   = 0x30;
617 const binary MATROSKA_DVD_LEVEL_LU   = 0x2A;
618 const binary MATROSKA_DVD_LEVEL_TT   = 0x28;
619 const binary MATROSKA_DVD_LEVEL_PGC  = 0x20;
620 const binary MATROSKA_DVD_LEVEL_PG   = 0x18;
621 const binary MATROSKA_DVD_LEVEL_PTT  = 0x10;
622 const binary MATROSKA_DVD_LEVEL_CN   = 0x08;
623
624 class chapter_codec_cmds_c
625 {
626 public:
627     chapter_codec_cmds_c( demux_sys_t & demuxer, int codec_id = -1)
628     :p_private_data(NULL)
629     ,i_codec_id( codec_id )
630     ,sys( demuxer )
631     {}
632         
633     virtual ~chapter_codec_cmds_c() 
634     {
635         delete p_private_data;
636         std::vector<KaxChapterProcessData*>::iterator indexe = enter_cmds.begin();
637         while ( indexe != enter_cmds.end() )
638         {
639             delete (*indexe);
640             indexe++;
641         }
642         std::vector<KaxChapterProcessData*>::iterator indexl = leave_cmds.begin();
643         while ( indexl != leave_cmds.end() )
644         {
645             delete (*indexl);
646             indexl++;
647         }
648         std::vector<KaxChapterProcessData*>::iterator indexd = during_cmds.begin();
649         while ( indexd != during_cmds.end() )
650         {
651             delete (*indexd);
652             indexd++;
653         }
654     }
655
656     void SetPrivate( const KaxChapterProcessPrivate & private_data )
657     {
658         p_private_data = new KaxChapterProcessPrivate( private_data );
659     }
660
661     void AddCommand( const KaxChapterProcessCommand & command );
662     
663     /// \return wether the codec has seeked in the files or not
664     virtual bool Enter() { return false; }
665     virtual bool Leave() { return false; }
666     virtual std::string GetCodecName( bool f_for_title = false ) const { return ""; }
667     virtual int16 GetTitleNumber() { return -1; }
668
669     KaxChapterProcessPrivate *p_private_data;
670
671 protected:
672     std::vector<KaxChapterProcessData*> enter_cmds;
673     std::vector<KaxChapterProcessData*> during_cmds;
674     std::vector<KaxChapterProcessData*> leave_cmds;
675
676     int i_codec_id;
677     demux_sys_t & sys;
678 };
679
680 class dvd_command_interpretor_c
681 {
682 public:
683     dvd_command_interpretor_c( demux_sys_t & demuxer )
684     :sys( demuxer )
685     {
686         memset( p_PRMs, 0, sizeof(p_PRMs) );
687         p_PRMs[ 0x80 + 1 ] = 15;
688         p_PRMs[ 0x80 + 2 ] = 62;
689         p_PRMs[ 0x80 + 3 ] = 1;
690         p_PRMs[ 0x80 + 4 ] = 1;
691         p_PRMs[ 0x80 + 7 ] = 1;
692         p_PRMs[ 0x80 + 8 ] = 1;
693         p_PRMs[ 0x80 + 16 ] = 0xFFFFu;
694         p_PRMs[ 0x80 + 18 ] = 0xFFFFu;
695     }
696     
697     bool Interpret( const binary * p_command, size_t i_size = 8 );
698     
699     uint16 GetPRM( size_t index ) const
700     {
701         if ( index < 256 )
702             return p_PRMs[ index ];
703         else return 0;
704     }
705
706     uint16 GetGPRM( size_t index ) const
707     {
708         if ( index >= 0 && index < 16 )
709             return p_PRMs[ index ];
710         else return 0;
711     }
712
713     uint16 GetSPRM( size_t index ) const
714     {
715         // 21,22,23 reserved for future use
716         if ( index >= 0x80 && index < 0x95 )
717             return p_PRMs[ index ];
718         else return 0;
719     }
720
721     bool SetPRM( size_t index, uint16 value )
722     {
723         if ( index >= 0 && index < 16 )
724         {
725             p_PRMs[ index ] = value;
726             return true;
727         }
728         return false;
729     }
730     
731     bool SetGPRM( size_t index, uint16 value )
732     {
733         if ( index >= 0 && index < 16 )
734         {
735             p_PRMs[ index ] = value;
736             return true;
737         }
738         return false;
739     }
740
741     bool SetSPRM( size_t index, uint16 value )
742     {
743         if ( index > 0x80 && index <= 0x8D && index != 0x8C )
744         {
745             p_PRMs[ index ] = value;
746             return true;
747         }
748         return false;
749     }
750
751 protected:
752     std::string GetRegTypeName( bool b_value, uint16 value ) const
753     {
754         std::string result;
755         char s_value[6], s_reg_value[6];
756         sprintf( s_value, "%.5d", value );
757
758         if ( b_value )
759         {
760             result = "value (";
761             result += s_value;
762             result += ")";
763         }
764         else if ( value < 0x80 )
765         {
766             sprintf( s_reg_value, "%.5d", GetPRM( value ) );
767             result = "GPreg[";
768             result += s_value;
769             result += "] (";
770             result += s_reg_value;
771             result += ")";
772         }
773         else
774         {
775             sprintf( s_reg_value, "%.5d", GetPRM( value ) );
776             result = "SPreg[";
777             result += s_value;
778             result += "] (";
779             result += s_reg_value;
780             result += ")";
781         }
782         return result;
783     }
784
785     uint16       p_PRMs[256];
786     demux_sys_t  & sys;
787     
788     // DVD command IDs
789
790     // Tests
791     // wether it's a comparison on the value or register
792     static const uint16 CMD_DVD_TEST_VALUE          = 0x80;
793     static const uint16 CMD_DVD_IF_GPREG_AND        = (1 << 4);
794     static const uint16 CMD_DVD_IF_GPREG_EQUAL      = (2 << 4);
795     static const uint16 CMD_DVD_IF_GPREG_NOT_EQUAL  = (3 << 4);
796     static const uint16 CMD_DVD_IF_GPREG_SUP_EQUAL  = (4 << 4);
797     static const uint16 CMD_DVD_IF_GPREG_SUP        = (5 << 4);
798     static const uint16 CMD_DVD_IF_GPREG_INF_EQUAL  = (6 << 4);
799     static const uint16 CMD_DVD_IF_GPREG_INF        = (7 << 4);
800     
801     static const uint16 CMD_DVD_NOP                    = 0x0000;
802     static const uint16 CMD_DVD_GOTO_LINE              = 0x0001;
803     static const uint16 CMD_DVD_BREAK                  = 0x0002;
804     // Links
805     static const uint16 CMD_DVD_NOP2                   = 0x2001;
806     static const uint16 CMD_DVD_LINKPGCN               = 0x2004;
807     static const uint16 CMD_DVD_LINKPGN                = 0x2006;
808     static const uint16 CMD_DVD_LINKCN                 = 0x2007;
809     static const uint16 CMD_DVD_JUMP_TT                = 0x3002;
810     static const uint16 CMD_DVD_JUMPVTS_TT             = 0x3003;
811     static const uint16 CMD_DVD_JUMPVTS_PTT            = 0x3005;
812     static const uint16 CMD_DVD_JUMP_SS                = 0x3006;
813     static const uint16 CMD_DVD_CALLSS_VTSM1           = 0x3008;
814     //
815     static const uint16 CMD_DVD_SET_HL_BTNN2           = 0x4600;
816     static const uint16 CMD_DVD_SET_HL_BTNN_LINKPGCN1  = 0x4604;
817     static const uint16 CMD_DVD_SET_STREAM             = 0x5100;
818     static const uint16 CMD_DVD_SET_GPRMMD             = 0x5300;
819     static const uint16 CMD_DVD_SET_HL_BTNN1           = 0x5600;
820     static const uint16 CMD_DVD_SET_HL_BTNN_LINKPGCN2  = 0x5604;
821     static const uint16 CMD_DVD_SET_HL_BTNN_LINKCN     = 0x5607;
822     // Operations
823     static const uint16 CMD_DVD_MOV_SPREG_PREG         = 0x6100;
824     static const uint16 CMD_DVD_GPREG_MOV_VALUE        = 0x7100;
825     static const uint16 CMD_DVD_SUB_GPREG              = 0x7400;
826     static const uint16 CMD_DVD_MULT_GPREG             = 0x7500;
827     static const uint16 CMD_DVD_GPREG_DIV_VALUE        = 0x7600;
828     static const uint16 CMD_DVD_GPREG_AND_VALUE        = 0x7900;
829     
830     // callbacks when browsing inside CodecPrivate
831     static bool MatchIsDomain     ( const chapter_codec_cmds_c &data, const void *p_cookie, size_t i_cookie_size );
832     static bool MatchIsVMG        ( const chapter_codec_cmds_c &data, const void *p_cookie, size_t i_cookie_size );
833     static bool MatchVTSNumber    ( const chapter_codec_cmds_c &data, const void *p_cookie, size_t i_cookie_size );
834     static bool MatchVTSMNumber   ( const chapter_codec_cmds_c &data, const void *p_cookie, size_t i_cookie_size );
835     static bool MatchTitleNumber  ( const chapter_codec_cmds_c &data, const void *p_cookie, size_t i_cookie_size );
836     static bool MatchPgcType      ( const chapter_codec_cmds_c &data, const void *p_cookie, size_t i_cookie_size );
837     static bool MatchPgcNumber    ( const chapter_codec_cmds_c &data, const void *p_cookie, size_t i_cookie_size );
838     static bool MatchChapterNumber( const chapter_codec_cmds_c &data, const void *p_cookie, size_t i_cookie_size );
839     static bool MatchCellNumber   ( const chapter_codec_cmds_c &data, const void *p_cookie, size_t i_cookie_size );
840 };
841
842 class dvd_chapter_codec_c : public chapter_codec_cmds_c
843 {
844 public:
845     dvd_chapter_codec_c( demux_sys_t & sys )
846     :chapter_codec_cmds_c( sys, 1 )
847     {}
848
849     bool Enter();
850     bool Leave();
851     std::string GetCodecName( bool f_for_title = false ) const;
852     int16 GetTitleNumber();
853 };
854
855 class matroska_script_interpretor_c
856 {
857 public:
858     matroska_script_interpretor_c( demux_sys_t & demuxer )
859     :sys( demuxer )
860     {}
861
862     bool Interpret( const binary * p_command, size_t i_size );
863     
864     // DVD command IDs
865     static const std::string CMD_MS_GOTO_AND_PLAY;
866     
867 protected:
868     demux_sys_t  & sys;
869 };
870
871 const std::string matroska_script_interpretor_c::CMD_MS_GOTO_AND_PLAY = "GotoAndPlay";
872
873
874 class matroska_script_codec_c : public chapter_codec_cmds_c
875 {
876 public:
877     matroska_script_codec_c( demux_sys_t & sys )
878     :chapter_codec_cmds_c( sys, 0 )
879     ,interpretor( sys )
880     {}
881
882     bool Enter();
883     bool Leave();
884
885 protected:
886     matroska_script_interpretor_c interpretor; 
887 };
888
889 class chapter_translation_c
890 {
891 public:
892     chapter_translation_c()
893         :p_translated(NULL)
894     {}
895
896     ~chapter_translation_c()
897     {
898         delete p_translated;
899     }
900
901     KaxChapterTranslateID  *p_translated;
902     unsigned int           codec_id;
903     std::vector<uint64_t>  editions;
904 };
905
906 class chapter_item_c
907 {
908 public:
909     chapter_item_c()
910     :i_start_time(0)
911     ,i_end_time(-1)
912     ,i_user_start_time(-1)
913     ,i_user_end_time(-1)
914     ,i_seekpoint_num(-1)
915     ,b_display_seekpoint(true)
916     ,b_user_display(false)
917     ,psz_parent(NULL)
918     ,b_is_leaving(false)
919     {}
920
921     virtual ~chapter_item_c()
922     {
923         std::vector<chapter_codec_cmds_c*>::iterator index = codecs.begin();
924         while ( index != codecs.end() )
925         {
926             delete (*index);
927             index++;
928         }
929         std::vector<chapter_item_c*>::iterator index_ = sub_chapters.begin();
930         while ( index_ != sub_chapters.end() )
931         {
932             delete (*index_);
933             index_++;
934         }
935     }
936
937     int64_t RefreshChapters( bool b_ordered, int64_t i_prev_user_time );
938     int PublishChapters( input_title_t & title, int & i_user_chapters, int i_level = 0 );
939     virtual chapter_item_c * FindTimecode( mtime_t i_timecode, const chapter_item_c * p_current, bool & b_found );
940     void Append( const chapter_item_c & edition );
941     chapter_item_c * FindChapter( int64_t i_find_uid );
942     virtual chapter_item_c *BrowseCodecPrivate( unsigned int codec_id, 
943                                     bool (*match)(const chapter_codec_cmds_c &data, const void *p_cookie, size_t i_cookie_size ), 
944                                     const void *p_cookie, 
945                                     size_t i_cookie_size );
946     std::string                 GetCodecName( bool f_for_title = false ) const;
947     bool                        ParentOf( const chapter_item_c & item ) const;
948     int16                       GetTitleNumber( ) const;
949     
950     int64_t                     i_start_time, i_end_time;
951     int64_t                     i_user_start_time, i_user_end_time; /* the time in the stream when an edition is ordered */
952     std::vector<chapter_item_c*> sub_chapters;
953     int                         i_seekpoint_num;
954     int64_t                     i_uid;
955     bool                        b_display_seekpoint;
956     bool                        b_user_display;
957     std::string                 psz_name;
958     chapter_item_c              *psz_parent;
959     bool                        b_is_leaving;
960     
961     std::vector<chapter_codec_cmds_c*> codecs;
962
963     static bool CompareTimecode( const chapter_item_c * itemA, const chapter_item_c * itemB )
964     {
965         return ( itemA->i_user_start_time < itemB->i_user_start_time || (itemA->i_user_start_time == itemB->i_user_start_time && itemA->i_user_end_time < itemB->i_user_end_time) );
966     }
967
968     bool Enter( bool b_do_subchapters );
969     bool Leave( bool b_do_subchapters );
970     bool EnterAndLeave( chapter_item_c *p_item, bool b_enter = true );
971 };
972
973 class chapter_edition_c : public chapter_item_c
974 {
975 public:
976     chapter_edition_c()
977     :b_ordered(false)
978     {}
979     
980     void RefreshChapters( );
981     mtime_t Duration() const;
982     std::string GetMainName() const;
983     chapter_item_c * FindTimecode( mtime_t i_timecode, const chapter_item_c * p_current );
984     
985     bool                        b_ordered;
986 };
987
988 class matroska_segment_c
989 {
990 public:
991     matroska_segment_c( demux_sys_t & demuxer, EbmlStream & estream )
992         :segment(NULL)
993         ,es(estream)
994         ,i_timescale(MKVD_TIMECODESCALE)
995         ,i_duration(-1)
996         ,i_start_time(0)
997         ,i_cues_position(-1)
998         ,i_chapters_position(-1)
999         ,i_tags_position(-1)
1000         ,cluster(NULL)
1001         ,i_block_pos(0)
1002         ,i_cluster_pos(0)
1003         ,i_start_pos(0)
1004         ,p_segment_uid(NULL)
1005         ,p_prev_segment_uid(NULL)
1006         ,p_next_segment_uid(NULL)
1007         ,b_cues(VLC_FALSE)
1008         ,i_index(0)
1009         ,i_index_max(1024)
1010         ,psz_muxing_application(NULL)
1011         ,psz_writing_application(NULL)
1012         ,psz_segment_filename(NULL)
1013         ,psz_title(NULL)
1014         ,psz_date_utc(NULL)
1015         ,i_default_edition(0)
1016         ,sys(demuxer)
1017         ,ep(NULL)
1018         ,b_preloaded(false)
1019     {
1020         p_indexes = (mkv_index_t*)malloc( sizeof( mkv_index_t ) * i_index_max );
1021     }
1022
1023     virtual ~matroska_segment_c()
1024     {
1025         for( size_t i_track = 0; i_track < tracks.size(); i_track++ )
1026         {
1027             if( tracks[i_track]->fmt.psz_description )
1028             {
1029                 free( tracks[i_track]->fmt.psz_description );
1030             }
1031             if( tracks[i_track]->psz_codec )
1032             {
1033                 free( tracks[i_track]->psz_codec );
1034             }
1035             if( tracks[i_track]->fmt.psz_language )
1036             {
1037                 free( tracks[i_track]->fmt.psz_language );
1038             }
1039             delete tracks[i_track];
1040         }
1041         
1042         if( psz_writing_application )
1043         {
1044             free( psz_writing_application );
1045         }
1046         if( psz_muxing_application )
1047         {
1048             free( psz_muxing_application );
1049         }
1050         if( psz_segment_filename )
1051         {
1052             free( psz_segment_filename );
1053         }
1054         if( psz_title )
1055         {
1056             free( psz_title );
1057         }
1058         if( psz_date_utc )
1059         {
1060             free( psz_date_utc );
1061         }
1062         if ( p_indexes )
1063             free( p_indexes );
1064
1065         delete ep;
1066         delete segment;
1067         delete p_segment_uid;
1068         delete p_prev_segment_uid;
1069         delete p_next_segment_uid;
1070
1071         std::vector<chapter_edition_c*>::iterator index = stored_editions.begin();
1072         while ( index != stored_editions.end() )
1073         {
1074             delete (*index);
1075             index++;
1076         }
1077         std::vector<chapter_translation_c*>::iterator indext = translations.begin();
1078         while ( indext != translations.end() )
1079         {
1080             delete (*indext);
1081             indext++;
1082         }
1083         std::vector<KaxSegmentFamily*>::iterator indexf = families.begin();
1084         while ( indexf != families.end() )
1085         {
1086             delete (*indexf);
1087             indexf++;
1088         }
1089     }
1090
1091     KaxSegment              *segment;
1092     EbmlStream              & es;
1093
1094     /* time scale */
1095     uint64_t                i_timescale;
1096
1097     /* duration of the segment */
1098     mtime_t                 i_duration;
1099     mtime_t                 i_start_time;
1100
1101     /* all tracks */
1102     std::vector<mkv_track_t*> tracks;
1103
1104     /* from seekhead */
1105     int64_t                 i_cues_position;
1106     int64_t                 i_chapters_position;
1107     int64_t                 i_tags_position;
1108
1109     KaxCluster              *cluster;
1110     uint64                  i_block_pos;
1111     uint64                  i_cluster_pos;
1112     int64_t                 i_start_pos;
1113     KaxSegmentUID           *p_segment_uid;
1114     KaxPrevUID              *p_prev_segment_uid;
1115     KaxNextUID              *p_next_segment_uid;
1116
1117     vlc_bool_t              b_cues;
1118     int                     i_index;
1119     int                     i_index_max;
1120     mkv_index_t             *p_indexes;
1121
1122     /* info */
1123     char                    *psz_muxing_application;
1124     char                    *psz_writing_application;
1125     char                    *psz_segment_filename;
1126     char                    *psz_title;
1127     char                    *psz_date_utc;
1128
1129     /* !!!!! GCC 3.3 bug on Darwin !!!!! */
1130     /* when you remove this variable the compiler issues an atomicity error */
1131     /* this variable only works when using std::vector<chapter_edition_c> */
1132     std::vector<chapter_edition_c*> stored_editions;
1133     int                             i_default_edition;
1134
1135     std::vector<chapter_translation_c*> translations;
1136     std::vector<KaxSegmentFamily*>  families;
1137     
1138     demux_sys_t                    & sys;
1139     EbmlParser                     *ep;
1140     bool                           b_preloaded;
1141
1142     bool Preload( );
1143     bool PreloadFamily( const matroska_segment_c & segment );
1144     void ParseInfo( KaxInfo *info );
1145     void ParseChapters( KaxChapters *chapters );
1146     void ParseSeekHead( KaxSeekHead *seekhead );
1147     void ParseTracks( KaxTracks *tracks );
1148     void ParseChapterAtom( int i_level, KaxChapterAtom *ca, chapter_item_c & chapters );
1149     void ParseTrackEntry( KaxTrackEntry *m );
1150     void ParseCluster( );
1151     void IndexAppendCluster( KaxCluster *cluster );
1152     void LoadCues( );
1153     void LoadTags( );
1154     void InformationCreate( );
1155     void Seek( mtime_t i_date, mtime_t i_time_offset );
1156     int BlockGet( KaxBlock * & pp_block, int64_t *pi_ref1, int64_t *pi_ref2, int64_t *pi_duration );
1157     bool Select( mtime_t i_start_time );
1158     void UnSelect( );
1159
1160     static bool CompareSegmentUIDs( const matroska_segment_c * item_a, const matroska_segment_c * item_b );
1161 };
1162
1163 // class holding hard-linked segment together in the playback order
1164 class virtual_segment_c
1165 {
1166 public:
1167     virtual_segment_c( matroska_segment_c *p_segment )
1168         :p_editions(NULL)
1169         ,i_sys_title(0)
1170         ,i_current_segment(0)
1171         ,i_current_edition(-1)
1172         ,psz_current_chapter(NULL)
1173     {
1174         linked_segments.push_back( p_segment );
1175
1176         AppendUID( p_segment->p_segment_uid );
1177         AppendUID( p_segment->p_prev_segment_uid );
1178         AppendUID( p_segment->p_next_segment_uid );
1179     }
1180
1181     void Sort();
1182     size_t AddSegment( matroska_segment_c *p_segment );
1183     void PreloadLinked( );
1184     mtime_t Duration( ) const;
1185     void LoadCues( );
1186     void Seek( demux_t & demuxer, mtime_t i_date, mtime_t i_time_offset, chapter_item_c *psz_chapter );
1187
1188     inline chapter_edition_c *Edition()
1189     {
1190         if ( i_current_edition >= 0 && size_t(i_current_edition) < p_editions->size() )
1191             return (*p_editions)[i_current_edition];
1192         return NULL;
1193     }
1194
1195     matroska_segment_c * Segment() const
1196     {
1197         if ( linked_segments.size() == 0 || i_current_segment >= linked_segments.size() )
1198             return NULL;
1199         return linked_segments[i_current_segment];
1200     }
1201
1202     inline chapter_item_c *CurrentChapter() {
1203         return psz_current_chapter;
1204     }
1205
1206     bool SelectNext()
1207     {
1208         if ( i_current_segment < linked_segments.size()-1 )
1209         {
1210             i_current_segment++;
1211             return true;
1212         }
1213         return false;
1214     }
1215
1216     bool FindUID( KaxSegmentUID & uid ) const
1217     {
1218         for ( size_t i=0; i<linked_uids.size(); i++ )
1219         {
1220             if ( linked_uids[i] == uid )
1221                 return true;
1222         }
1223         return false;
1224     }
1225
1226     bool UpdateCurrentToChapter( demux_t & demux );
1227     void PrepareChapters( );
1228
1229     chapter_item_c *BrowseCodecPrivate( unsigned int codec_id, 
1230                                         bool (*match)(const chapter_codec_cmds_c &data, const void *p_cookie, size_t i_cookie_size ), 
1231                                         const void *p_cookie, 
1232                                         size_t i_cookie_size );
1233     chapter_item_c *FindChapter( int64_t i_find_uid );
1234
1235     std::vector<chapter_edition_c*>  *p_editions;
1236     int                              i_sys_title;
1237
1238 protected:
1239     std::vector<matroska_segment_c*> linked_segments;
1240     std::vector<KaxSegmentUID>       linked_uids;
1241     size_t                           i_current_segment;
1242
1243     int                              i_current_edition;
1244     chapter_item_c                   *psz_current_chapter;
1245
1246     void                             AppendUID( const EbmlBinary * UID );
1247 };
1248
1249 class matroska_stream_c
1250 {
1251 public:
1252     matroska_stream_c( demux_sys_t & demuxer )
1253         :p_in(NULL)
1254         ,p_es(NULL)
1255         ,sys(demuxer)
1256     {}
1257
1258     virtual ~matroska_stream_c()
1259     {
1260         delete p_in;
1261         delete p_es;
1262     }
1263
1264     IOCallback         *p_in;
1265     EbmlStream         *p_es;
1266
1267     std::vector<matroska_segment_c*> segments;
1268
1269     demux_sys_t                      & sys;
1270 };
1271
1272 typedef struct
1273 {
1274     VLC_COMMON_MEMBERS
1275
1276     demux_t        *p_demux;
1277     vlc_mutex_t     lock;
1278
1279     vlc_bool_t      b_moved;
1280     vlc_bool_t      b_clicked;
1281     vlc_bool_t      b_key;
1282
1283 } event_thread_t;
1284
1285 class demux_sys_t
1286 {
1287 public:
1288     demux_sys_t( demux_t & demux )
1289         :demuxer(demux)
1290         ,i_pts(0)
1291         ,i_start_pts(0)
1292         ,i_chapter_time(0)
1293         ,meta(NULL)
1294         ,i_current_title(0)
1295         ,p_current_segment(NULL)
1296         ,dvd_interpretor( *this )
1297         ,f_duration(-1.0)
1298         ,b_ui_hooked(false)
1299         ,p_input(NULL)
1300         ,b_pci_packet_set(false)
1301         ,p_ev(NULL)
1302     {
1303         vlc_mutex_init( &demuxer, &lock_demuxer );
1304     }
1305
1306     virtual ~demux_sys_t()
1307     {
1308         StopUiThread();
1309         size_t i;
1310         for ( i=0; i<streams.size(); i++ )
1311             delete streams[i];
1312         for ( i=0; i<opened_segments.size(); i++ )
1313             delete opened_segments[i];
1314         for ( i=0; i<used_segments.size(); i++ )
1315             delete used_segments[i];
1316         vlc_mutex_destroy( &lock_demuxer );
1317     }
1318
1319     /* current data */
1320     demux_t                 & demuxer;
1321
1322     mtime_t                 i_pts;
1323     mtime_t                 i_start_pts;
1324     mtime_t                 i_chapter_time;
1325
1326     vlc_meta_t              *meta;
1327
1328     std::vector<input_title_t*>      titles; // matroska editions
1329     size_t                           i_current_title;
1330
1331     std::vector<matroska_stream_c*>  streams;
1332     std::vector<matroska_segment_c*> opened_segments;
1333     std::vector<virtual_segment_c*>  used_segments;
1334     virtual_segment_c                *p_current_segment;
1335
1336     dvd_command_interpretor_c        dvd_interpretor;
1337
1338     /* duration of the stream */
1339     float                   f_duration;
1340
1341     matroska_segment_c *FindSegment( const EbmlBinary & uid ) const;
1342     chapter_item_c *BrowseCodecPrivate( unsigned int codec_id, 
1343                                         bool (*match)(const chapter_codec_cmds_c &data, const void *p_cookie, size_t i_cookie_size ), 
1344                                         const void *p_cookie, 
1345                                         size_t i_cookie_size, 
1346                                         virtual_segment_c * & p_segment_found );
1347     chapter_item_c *FindChapter( int64_t i_find_uid, virtual_segment_c * & p_segment_found );
1348
1349     void PreloadFamily( const matroska_segment_c & of_segment );
1350     void PreloadLinked( matroska_segment_c *p_segment );
1351     bool PreparePlayback( virtual_segment_c *p_new_segment );
1352     matroska_stream_c *AnalyseAllSegmentsFound( EbmlStream *p_estream, bool b_initial = false );
1353     void JumpTo( virtual_segment_c & p_segment, chapter_item_c * p_chapter );
1354
1355     void StartUiThread();
1356     void StopUiThread();
1357     bool b_ui_hooked;
1358     inline void SwapButtons();
1359
1360     /* for spu variables */
1361     input_thread_t *p_input;
1362     pci_t          pci_packet;
1363     bool           b_pci_packet_set;
1364     uint8_t        palette[4][4];
1365     vlc_mutex_t    lock_demuxer;
1366
1367     /* event */
1368     event_thread_t *p_ev;
1369     static int EventThread( vlc_object_t *p_this );
1370     static int EventMouse( vlc_object_t *p_this, char const *psz_var,
1371                        vlc_value_t oldval, vlc_value_t newval, void *p_data );
1372     static int EventKey( vlc_object_t *p_this, char const *psz_var,
1373                      vlc_value_t oldval, vlc_value_t newval, void *p_data );
1374
1375
1376
1377 protected:
1378     virtual_segment_c *VirtualFromSegments( matroska_segment_c *p_segment ) const;
1379     bool IsUsedSegment( matroska_segment_c &p_segment ) const;
1380 };
1381
1382 static int  Demux  ( demux_t * );
1383 static int  Control( demux_t *, int, va_list );
1384 static void Seek   ( demux_t *, mtime_t i_date, double f_percent, chapter_item_c *psz_chapter );
1385
1386 #define MKV_IS_ID( el, C ) ( EbmlId( (*el) ) == C::ClassInfos.GlobalId )
1387
1388 static inline char * ToUTF8( const UTFstring &u )
1389 {
1390     return strdup( u.GetUTF8().c_str() );
1391 }
1392
1393 /*****************************************************************************
1394  * Open: initializes matroska demux structures
1395  *****************************************************************************/
1396 static int Open( vlc_object_t * p_this )
1397 {
1398     demux_t            *p_demux = (demux_t*)p_this;
1399     demux_sys_t        *p_sys;
1400     matroska_stream_c  *p_stream;
1401     matroska_segment_c *p_segment;
1402     uint8_t            *p_peek;
1403     std::string        s_path, s_filename;
1404     vlc_stream_io_callback *p_io_callback;
1405     EbmlStream         *p_io_stream;
1406
1407     /* peek the begining */
1408     if( stream_Peek( p_demux->s, &p_peek, 4 ) < 4 ) return VLC_EGENERIC;
1409
1410     /* is a valid file */
1411     if( p_peek[0] != 0x1a || p_peek[1] != 0x45 ||
1412         p_peek[2] != 0xdf || p_peek[3] != 0xa3 ) return VLC_EGENERIC;
1413
1414     /* Set the demux function */
1415     p_demux->pf_demux   = Demux;
1416     p_demux->pf_control = Control;
1417     p_demux->p_sys      = p_sys = new demux_sys_t( *p_demux );
1418
1419     p_io_callback = new vlc_stream_io_callback( p_demux->s, VLC_FALSE );
1420     p_io_stream = new EbmlStream( *p_io_callback );
1421
1422     if( p_io_stream == NULL )
1423     {
1424         msg_Err( p_demux, "failed to create EbmlStream" );
1425         delete p_io_callback;
1426         delete p_sys;
1427         return VLC_EGENERIC;
1428     }
1429
1430     p_stream = p_sys->AnalyseAllSegmentsFound( p_io_stream, true );
1431     if( p_stream == NULL )
1432     {
1433         msg_Err( p_demux, "cannot find KaxSegment" );
1434         goto error;
1435     }
1436     p_sys->streams.push_back( p_stream );
1437
1438     p_stream->p_in = p_io_callback;
1439     p_stream->p_es = p_io_stream;
1440
1441     for (size_t i=0; i<p_stream->segments.size(); i++)
1442     {
1443         p_stream->segments[i]->Preload();
1444     }
1445
1446     p_segment = p_stream->segments[0];
1447     if( p_segment->cluster != NULL )
1448     {
1449         msg_Warn( p_demux, "cannot find any cluster, damaged file ?" );
1450
1451         // reset the stream reading to the first cluster of the segment used
1452         p_stream->p_in->setFilePointer( p_segment->cluster->GetElementPosition() );
1453     }
1454
1455     /* get the files from the same dir from the same family (based on p_demux->psz_path) */
1456     if (p_demux->psz_path[0] != '\0' && !strcmp(p_demux->psz_access, ""))
1457     {
1458         // assume it's a regular file
1459         // get the directory path
1460         s_path = p_demux->psz_path;
1461         if (s_path.at(s_path.length() - 1) == DIRECTORY_SEPARATOR)
1462         {
1463             s_path = s_path.substr(0,s_path.length()-1);
1464         }
1465         else
1466         {
1467             if (s_path.find_last_of(DIRECTORY_SEPARATOR) > 0) 
1468             {
1469                 s_path = s_path.substr(0,s_path.find_last_of(DIRECTORY_SEPARATOR));
1470             }
1471         }
1472
1473         struct dirent *p_file_item;
1474         DIR *p_src_dir = opendir(s_path.c_str());
1475
1476         if (p_src_dir != NULL)
1477         {
1478             while ((p_file_item = (dirent *) readdir(p_src_dir)))
1479             {
1480                 if (strlen(p_file_item->d_name) > 4)
1481                 {
1482                     s_filename = s_path + DIRECTORY_SEPARATOR + p_file_item->d_name;
1483
1484                     if (!s_filename.compare(p_demux->psz_path))
1485                         continue; // don't reuse the original opened file
1486
1487 #if defined(__GNUC__) && (__GNUC__ < 3)
1488                     if (!s_filename.compare("mkv", s_filename.length() - 3, 3) || 
1489                         !s_filename.compare("mka", s_filename.length() - 3, 3))
1490 #else
1491                     if (!s_filename.compare(s_filename.length() - 3, 3, "mkv") || 
1492                         !s_filename.compare(s_filename.length() - 3, 3, "mka"))
1493 #endif
1494                     {
1495                         // test wether this file belongs to our family
1496                         stream_t *p_file_stream = stream_UrlNew( p_demux, s_filename.c_str());
1497                         if ( p_file_stream != NULL )
1498                         {
1499                             vlc_stream_io_callback *p_file_io = new vlc_stream_io_callback( p_file_stream, VLC_TRUE );
1500                             EbmlStream *p_estream = new EbmlStream(*p_file_io);
1501
1502                             p_stream = p_sys->AnalyseAllSegmentsFound( p_estream );
1503
1504                             if ( p_stream == NULL )
1505                             {
1506                                 msg_Dbg( p_demux, "the file '%s' will not be used", s_filename.c_str() );
1507                                 delete p_estream;
1508                                 delete p_file_io;
1509                             }
1510                             else
1511                             {
1512                                 p_stream->p_in = p_file_io;
1513                                 p_stream->p_es = p_estream;
1514                                 p_sys->streams.push_back( p_stream );
1515                             }
1516                         }
1517                         else
1518                         {
1519                             msg_Dbg( p_demux, "the file '%s' cannot be opened", s_filename.c_str() );
1520                         }
1521                     }
1522                 }
1523             }
1524             closedir( p_src_dir );
1525         }
1526     }
1527
1528     p_sys->PreloadFamily( *p_segment );
1529     p_sys->PreloadLinked( p_segment );
1530     if ( !p_sys->PreparePlayback( NULL ) )
1531     {
1532         msg_Err( p_demux, "cannot use the segment" );
1533         goto error;
1534     }
1535
1536     p_sys->StartUiThread();
1537     
1538     return VLC_SUCCESS;
1539
1540 error:
1541     delete p_sys;
1542     return VLC_EGENERIC;
1543 }
1544
1545 /*****************************************************************************
1546  * Close: frees unused data
1547  *****************************************************************************/
1548 static void Close( vlc_object_t *p_this )
1549 {
1550     demux_t     *p_demux = (demux_t*)p_this;
1551     demux_sys_t *p_sys   = p_demux->p_sys;
1552
1553     delete p_sys;
1554 }
1555
1556 /*****************************************************************************
1557  * Control:
1558  *****************************************************************************/
1559 static int Control( demux_t *p_demux, int i_query, va_list args )
1560 {
1561     demux_sys_t        *p_sys = p_demux->p_sys;
1562     int64_t     *pi64;
1563     double      *pf, f;
1564     int         i_skp;
1565     size_t      i_idx;
1566
1567     vlc_meta_t **pp_meta;
1568
1569     switch( i_query )
1570     {
1571         case DEMUX_GET_META:
1572             pp_meta = (vlc_meta_t**)va_arg( args, vlc_meta_t** );
1573             *pp_meta = vlc_meta_Duplicate( p_sys->meta );
1574             return VLC_SUCCESS;
1575
1576         case DEMUX_GET_LENGTH:
1577             pi64 = (int64_t*)va_arg( args, int64_t * );
1578             if( p_sys->f_duration > 0.0 )
1579             {
1580                 *pi64 = (int64_t)(p_sys->f_duration * 1000);
1581                 return VLC_SUCCESS;
1582             }
1583             return VLC_EGENERIC;
1584
1585         case DEMUX_GET_POSITION:
1586             pf = (double*)va_arg( args, double * );
1587             if ( p_sys->f_duration > 0.0 )
1588                 *pf = (double)(p_sys->i_pts >= p_sys->i_start_pts ? p_sys->i_pts : p_sys->i_start_pts ) / (1000.0 * p_sys->f_duration);
1589             return VLC_SUCCESS;
1590
1591         case DEMUX_SET_POSITION:
1592             f = (double)va_arg( args, double );
1593             Seek( p_demux, -1, f, NULL );
1594             return VLC_SUCCESS;
1595
1596         case DEMUX_GET_TIME:
1597             pi64 = (int64_t*)va_arg( args, int64_t * );
1598             *pi64 = p_sys->i_pts;
1599             return VLC_SUCCESS;
1600
1601         case DEMUX_GET_TITLE_INFO:
1602             if( p_sys->titles.size() )
1603             {
1604                 input_title_t ***ppp_title = (input_title_t***)va_arg( args, input_title_t*** );
1605                 int *pi_int    = (int*)va_arg( args, int* );
1606
1607                 *pi_int = p_sys->titles.size();
1608                 *ppp_title = (input_title_t**)malloc( sizeof( input_title_t**) * p_sys->titles.size() );
1609
1610                 for( size_t i = 0; i < p_sys->titles.size(); i++ )
1611                 {
1612                     (*ppp_title)[i] = vlc_input_title_Duplicate( p_sys->titles[i] );
1613                 }
1614
1615                 return VLC_SUCCESS;
1616             }
1617             return VLC_EGENERIC;
1618
1619         case DEMUX_SET_TITLE:
1620             /* TODO handle editions as titles */
1621             i_idx = (int)va_arg( args, int );
1622             if( i_idx < p_sys->used_segments.size() )
1623             {
1624                 p_sys->JumpTo( *p_sys->used_segments[i_idx], NULL );
1625                 return VLC_SUCCESS;
1626             }
1627             return VLC_EGENERIC;
1628
1629         case DEMUX_SET_SEEKPOINT:
1630             i_skp = (int)va_arg( args, int );
1631
1632             // TODO change the way it works with the << & >> buttons on the UI (+1/-1 instead of a number)
1633             if( p_sys->titles.size() && i_skp < p_sys->titles[p_sys->i_current_title]->i_seekpoint)
1634             {
1635                 Seek( p_demux, (int64_t)p_sys->titles[p_sys->i_current_title]->seekpoint[i_skp]->i_time_offset, -1, NULL);
1636                 p_demux->info.i_seekpoint |= INPUT_UPDATE_SEEKPOINT;
1637                 p_demux->info.i_seekpoint = i_skp;
1638                 return VLC_SUCCESS;
1639             }
1640             return VLC_EGENERIC;
1641
1642         case DEMUX_SET_TIME:
1643         case DEMUX_GET_FPS:
1644         default:
1645             return VLC_EGENERIC;
1646     }
1647 }
1648
1649 int matroska_segment_c::BlockGet( KaxBlock * & pp_block, int64_t *pi_ref1, int64_t *pi_ref2, int64_t *pi_duration )
1650 {
1651     pp_block = NULL;
1652     *pi_ref1  = 0;
1653     *pi_ref2  = 0;
1654
1655     for( ;; )
1656     {
1657         EbmlElement *el;
1658         int         i_level;
1659
1660         if ( ep == NULL )
1661             return VLC_EGENERIC;
1662
1663         el = ep->Get();
1664         i_level = ep->GetLevel();
1665
1666         if( el == NULL && pp_block != NULL )
1667         {
1668             /* update the index */
1669 #define idx p_indexes[i_index - 1]
1670             if( i_index > 0 && idx.i_time == -1 )
1671             {
1672                 idx.i_time        = (*pp_block).GlobalTimecode() / (mtime_t)1000;
1673                 idx.b_key         = *pi_ref1 == 0 ? VLC_TRUE : VLC_FALSE;
1674             }
1675 #undef idx
1676             return VLC_SUCCESS;
1677         }
1678
1679         if( el == NULL )
1680         {
1681             if( ep->GetLevel() > 1 )
1682             {
1683                 ep->Up();
1684                 continue;
1685             }
1686             msg_Warn( &sys.demuxer, "EOF" );
1687             return VLC_EGENERIC;
1688         }
1689
1690         /* do parsing */
1691         switch ( i_level )
1692         {
1693         case 1:
1694             if( MKV_IS_ID( el, KaxCluster ) )
1695             {
1696                 cluster = (KaxCluster*)el;
1697                 i_cluster_pos = cluster->GetElementPosition();
1698
1699                 /* add it to the index */
1700                 if( i_index == 0 ||
1701                     ( i_index > 0 && p_indexes[i_index - 1].i_position < (int64_t)cluster->GetElementPosition() ) )
1702                 {
1703                     IndexAppendCluster( cluster );
1704                 }
1705
1706                 // reset silent tracks
1707                 for (size_t i=0; i<tracks.size(); i++)
1708                 {
1709                     tracks[i]->b_silent = VLC_FALSE;
1710                 }
1711
1712                 ep->Down();
1713             }
1714             else if( MKV_IS_ID( el, KaxCues ) )
1715             {
1716                 msg_Warn( &sys.demuxer, "find KaxCues FIXME" );
1717                 return VLC_EGENERIC;
1718             }
1719             else
1720             {
1721                 msg_Dbg( &sys.demuxer, "unknown (%s)", typeid( el ).name() );
1722             }
1723             break;
1724         case 2:
1725             if( MKV_IS_ID( el, KaxClusterTimecode ) )
1726             {
1727                 KaxClusterTimecode &ctc = *(KaxClusterTimecode*)el;
1728
1729                 ctc.ReadData( es.I_O(), SCOPE_ALL_DATA );
1730                 cluster->InitTimecode( uint64( ctc ), i_timescale );
1731             }
1732             else if( MKV_IS_ID( el, KaxClusterSilentTracks ) )
1733             {
1734                 ep->Down();
1735             }
1736             else if( MKV_IS_ID( el, KaxBlockGroup ) )
1737             {
1738                 i_block_pos = el->GetElementPosition();
1739                 ep->Down();
1740             }
1741             break;
1742         case 3:
1743             if( MKV_IS_ID( el, KaxBlock ) )
1744             {
1745                 pp_block = (KaxBlock*)el;
1746
1747                 pp_block->ReadData( es.I_O() );
1748                 pp_block->SetParent( *cluster );
1749
1750                 ep->Keep();
1751             }
1752             else if( MKV_IS_ID( el, KaxBlockDuration ) )
1753             {
1754                 KaxBlockDuration &dur = *(KaxBlockDuration*)el;
1755
1756                 dur.ReadData( es.I_O() );
1757                 *pi_duration = uint64( dur );
1758             }
1759             else if( MKV_IS_ID( el, KaxReferenceBlock ) )
1760             {
1761                 KaxReferenceBlock &ref = *(KaxReferenceBlock*)el;
1762
1763                 ref.ReadData( es.I_O() );
1764                 if( *pi_ref1 == 0 )
1765                 {
1766                     *pi_ref1 = int64( ref ) * cluster->GlobalTimecodeScale();
1767                 }
1768                 else
1769                 {
1770                     *pi_ref2 = int64( ref ) * cluster->GlobalTimecodeScale();
1771                 }
1772             }
1773             else if( MKV_IS_ID( el, KaxClusterSilentTrackNumber ) )
1774             {
1775                 KaxClusterSilentTrackNumber &track_num = *(KaxClusterSilentTrackNumber*)el;
1776                 track_num.ReadData( es.I_O() );
1777                 // find the track
1778                 for (size_t i=0; i<tracks.size(); i++)
1779                 {
1780                     if ( tracks[i]->i_number == uint32(track_num))
1781                     {
1782                         tracks[i]->b_silent = VLC_TRUE;
1783                         break;
1784                     }
1785                 }
1786             }
1787             break;
1788         default:
1789             msg_Err( &sys.demuxer, "invalid level = %d", i_level );
1790             return VLC_EGENERIC;
1791         }
1792     }
1793 }
1794
1795 static block_t *MemToBlock( demux_t *p_demux, uint8_t *p_mem, int i_mem)
1796 {
1797     block_t *p_block;
1798     if( !(p_block = block_New( p_demux, i_mem ) ) ) return NULL;
1799     memcpy( p_block->p_buffer, p_mem, i_mem );
1800     //p_block->i_rate = p_input->stream.control.i_rate;
1801     return p_block;
1802 }
1803
1804 static void BlockDecode( demux_t *p_demux, KaxBlock *block, mtime_t i_pts,
1805                          mtime_t i_duration, bool f_unreferenced )
1806 {
1807     demux_sys_t        *p_sys = p_demux->p_sys;
1808     matroska_segment_c *p_segment = p_sys->p_current_segment->Segment();
1809
1810     size_t          i_track;
1811     unsigned int    i;
1812     vlc_bool_t      b;
1813
1814 #define tk  p_segment->tracks[i_track]
1815     for( i_track = 0; i_track < p_segment->tracks.size(); i_track++ )
1816     {
1817         if( tk->i_number == block->TrackNum() )
1818         {
1819             break;
1820         }
1821     }
1822
1823     if( i_track >= p_segment->tracks.size() )
1824     {
1825         msg_Err( p_demux, "invalid track number=%d", block->TrackNum() );
1826         return;
1827     }
1828     if( tk->fmt.i_cat != NAV_ES && tk->p_es == NULL )
1829     {
1830         msg_Err( p_demux, "unknown track number=%d", block->TrackNum() );
1831         return;
1832     }
1833     if( i_pts + i_duration < p_sys->i_start_pts && tk->fmt.i_cat == AUDIO_ES )
1834     {
1835         return; /* discard audio packets that shouldn't be rendered */
1836     }
1837
1838     if ( tk->fmt.i_cat != NAV_ES )
1839     {
1840         es_out_Control( p_demux->out, ES_OUT_GET_ES_STATE, tk->p_es, &b );
1841
1842         if( !b )
1843         {
1844             tk->b_inited = VLC_FALSE;
1845             return;
1846         }
1847     }
1848
1849
1850     /* First send init data */
1851     if( !tk->b_inited && tk->i_data_init > 0 )
1852     {
1853         block_t *p_init;
1854
1855         msg_Dbg( p_demux, "sending header (%d bytes)", tk->i_data_init );
1856         p_init = MemToBlock( p_demux, tk->p_data_init, tk->i_data_init );
1857         if( p_init ) es_out_Send( p_demux->out, tk->p_es, p_init );
1858     }
1859     tk->b_inited = VLC_TRUE;
1860
1861
1862     for( i = 0; i < block->NumberFrames(); i++ )
1863     {
1864         block_t *p_block;
1865         DataBuffer &data = block->GetBuffer(i);
1866
1867         p_block = MemToBlock( p_demux, data.Buffer(), data.Size() );
1868
1869         if( p_block == NULL )
1870         {
1871             break;
1872         }
1873
1874 #if defined(HAVE_ZLIB_H)
1875         if( tk->i_compression_type )
1876         {
1877             p_block = block_zlib_decompress( VLC_OBJECT(p_demux), p_block );
1878         }
1879 #endif
1880
1881         if ( tk->fmt.i_cat == NAV_ES )
1882         {
1883             // TODO handle the start/stop times of this packet
1884             if ( p_sys->b_ui_hooked )
1885             {
1886                 vlc_mutex_lock( &p_sys->p_ev->lock );
1887                 memcpy( &p_sys->pci_packet, &p_block->p_buffer[1], sizeof(pci_t) );
1888                 p_sys->SwapButtons();
1889                 p_sys->b_pci_packet_set = true;
1890                 vlc_mutex_unlock( &p_sys->p_ev->lock );
1891                 block_Release( p_block );
1892             }
1893             return;
1894         }
1895         // correct timestamping when B frames are used
1896         if( tk->fmt.i_cat != VIDEO_ES )
1897         {
1898             p_block->i_dts = p_block->i_pts = i_pts;
1899         }
1900         else
1901         {
1902             if( !strcmp( tk->psz_codec, "V_MS/VFW/FOURCC" ) )
1903             {
1904                 // in VFW we have no idea about B frames
1905                 p_block->i_pts = 0;
1906                 p_block->i_dts = i_pts;
1907             }
1908             else
1909             {
1910                 p_block->i_pts = i_pts;
1911                 if ( f_unreferenced )
1912                     p_block->i_dts = p_block->i_pts;
1913                 else
1914                     p_block->i_dts = min( i_pts, tk->i_last_dts + (tk->i_default_duration >> 10));
1915                 p_sys->i_pts = p_block->i_dts;
1916             }
1917         }
1918         tk->i_last_dts = p_block->i_dts;
1919
1920 #if 0
1921 msg_Dbg( p_demux, "block i_dts: "I64Fd" / i_pts: "I64Fd, p_block->i_dts, p_block->i_pts);
1922 #endif
1923         if( strcmp( tk->psz_codec, "S_VOBSUB" ) )
1924         {
1925             p_block->i_length = i_duration * 1000;
1926         }
1927
1928         if( p_sys->i_pts >= p_sys->i_start_pts  )
1929         {
1930             es_out_Control( p_demux->out, ES_OUT_SET_PCR, p_sys->i_pts );
1931         }
1932
1933         es_out_Send( p_demux->out, tk->p_es, p_block );
1934
1935         /* use time stamp only for first block */
1936         i_pts = 0;
1937     }
1938
1939 #undef tk
1940 }
1941
1942 matroska_stream_c *demux_sys_t::AnalyseAllSegmentsFound( EbmlStream *p_estream, bool b_initial )
1943 {
1944     int i_upper_lvl = 0;
1945     size_t i;
1946     EbmlElement *p_l0, *p_l1, *p_l2;
1947     bool b_keep_stream = false, b_keep_segment;
1948
1949     // verify the EBML Header
1950     p_l0 = p_estream->FindNextID(EbmlHead::ClassInfos, 0xFFFFFFFFL);
1951     if (p_l0 == NULL)
1952     {
1953         return NULL;
1954     }
1955     p_l0->SkipData(*p_estream, KaxMatroska_Context);
1956     delete p_l0;
1957
1958     // find all segments in this file
1959     p_l0 = p_estream->FindNextID(KaxSegment::ClassInfos, 0xFFFFFFFFFLL);
1960     if (p_l0 == NULL)
1961     {
1962         return NULL;
1963     }
1964
1965     matroska_stream_c *p_stream1 = new matroska_stream_c( *this );
1966
1967     while (p_l0 != 0)
1968     {
1969         if (EbmlId(*p_l0) == KaxSegment::ClassInfos.GlobalId)
1970         {
1971             EbmlParser  *ep;
1972             matroska_segment_c *p_segment1 = new matroska_segment_c( *this, *p_estream );
1973             b_keep_segment = b_initial;
1974
1975             ep = new EbmlParser(p_estream, p_l0, &demuxer );
1976             p_segment1->ep = ep;
1977             p_segment1->segment = (KaxSegment*)p_l0;
1978
1979             while ((p_l1 = ep->Get()))
1980             {
1981                 if (MKV_IS_ID(p_l1, KaxInfo))
1982                 {
1983                     // find the families of this segment
1984                     KaxInfo *p_info = static_cast<KaxInfo*>(p_l1);
1985
1986                     p_info->Read(*p_estream, KaxInfo::ClassInfos.Context, i_upper_lvl, p_l2, true);
1987                     for( i = 0; i < p_info->ListSize(); i++ )
1988                     {
1989                         EbmlElement *l = (*p_info)[i];
1990
1991                         if( MKV_IS_ID( l, KaxSegmentUID ) )
1992                         {
1993                             KaxSegmentUID *p_uid = static_cast<KaxSegmentUID*>(l);
1994                             b_keep_segment = (FindSegment( *p_uid ) == NULL);
1995                             if ( !b_keep_segment )
1996                                 break; // this segment is already known
1997                             opened_segments.push_back( p_segment1 );
1998                             delete p_segment1->p_segment_uid;
1999                             p_segment1->p_segment_uid = new KaxSegmentUID(*p_uid);
2000                         }
2001                         else if( MKV_IS_ID( l, KaxPrevUID ) )
2002                         {
2003                             p_segment1->p_prev_segment_uid = new KaxPrevUID( *static_cast<KaxPrevUID*>(l) );
2004                         }
2005                         else if( MKV_IS_ID( l, KaxNextUID ) )
2006                         {
2007                             p_segment1->p_next_segment_uid = new KaxNextUID( *static_cast<KaxNextUID*>(l) );
2008                         }
2009                         else if( MKV_IS_ID( l, KaxSegmentFamily ) )
2010                         {
2011                             KaxSegmentFamily *p_fam = new KaxSegmentFamily( *static_cast<KaxSegmentFamily*>(l) );
2012                             p_segment1->families.push_back( p_fam );
2013                         }
2014                     }
2015                     break;
2016                 }
2017             }
2018             if ( b_keep_segment )
2019             {
2020                 b_keep_stream = true;
2021                 p_stream1->segments.push_back( p_segment1 );
2022             }
2023             else
2024                 delete p_segment1;
2025         }
2026         if (p_l0->IsFiniteSize() )
2027         {
2028             p_l0->SkipData(*p_estream, KaxMatroska_Context);
2029             p_l0 = p_estream->FindNextID(KaxSegment::ClassInfos, 0xFFFFFFFFL);
2030         }
2031         else
2032             p_l0 = p_l0->SkipData(*p_estream, KaxSegment_Context);
2033     }
2034
2035     if ( !b_keep_stream )
2036     {
2037         delete p_stream1;
2038         p_stream1 = NULL;
2039     }
2040
2041     return p_stream1;
2042 }
2043
2044 bool matroska_segment_c::Select( mtime_t i_start_time )
2045 {
2046     size_t i_track;
2047
2048     /* add all es */
2049     msg_Dbg( &sys.demuxer, "found %d es", (int)tracks.size() );
2050     sys.b_pci_packet_set = false;
2051
2052     for( i_track = 0; i_track < tracks.size(); i_track++ )
2053     {
2054         if( tracks[i_track]->fmt.i_cat == UNKNOWN_ES )
2055         {
2056             msg_Warn( &sys.demuxer, "invalid track[%d, n=%d]", (int)i_track, tracks[i_track]->i_number );
2057             tracks[i_track]->p_es = NULL;
2058             continue;
2059         }
2060
2061         if( !strcmp( tracks[i_track]->psz_codec, "V_MS/VFW/FOURCC" ) )
2062         {
2063             if( tracks[i_track]->i_extra_data < (int)sizeof( BITMAPINFOHEADER ) )
2064             {
2065                 msg_Err( &sys.demuxer, "missing/invalid BITMAPINFOHEADER" );
2066                 tracks[i_track]->fmt.i_codec = VLC_FOURCC( 'u', 'n', 'd', 'f' );
2067             }
2068             else
2069             {
2070                 BITMAPINFOHEADER *p_bih = (BITMAPINFOHEADER*)tracks[i_track]->p_extra_data;
2071
2072                 tracks[i_track]->fmt.video.i_width = GetDWLE( &p_bih->biWidth );
2073                 tracks[i_track]->fmt.video.i_height= GetDWLE( &p_bih->biHeight );
2074                 tracks[i_track]->fmt.i_codec       = GetFOURCC( &p_bih->biCompression );
2075
2076                 tracks[i_track]->fmt.i_extra       = GetDWLE( &p_bih->biSize ) - sizeof( BITMAPINFOHEADER );
2077                 if( tracks[i_track]->fmt.i_extra > 0 )
2078                 {
2079                     tracks[i_track]->fmt.p_extra = malloc( tracks[i_track]->fmt.i_extra );
2080                     memcpy( tracks[i_track]->fmt.p_extra, &p_bih[1], tracks[i_track]->fmt.i_extra );
2081                 }
2082             }
2083         }
2084         else if( !strcmp( tracks[i_track]->psz_codec, "V_MPEG1" ) ||
2085                  !strcmp( tracks[i_track]->psz_codec, "V_MPEG2" ) )
2086         {
2087             tracks[i_track]->fmt.i_codec = VLC_FOURCC( 'm', 'p', 'g', 'v' );
2088         }
2089         else if( !strncmp( tracks[i_track]->psz_codec, "V_MPEG4", 7 ) )
2090         {
2091             if( !strcmp( tracks[i_track]->psz_codec, "V_MPEG4/MS/V3" ) )
2092             {
2093                 tracks[i_track]->fmt.i_codec = VLC_FOURCC( 'D', 'I', 'V', '3' );
2094             }
2095             else if( !strcmp( tracks[i_track]->psz_codec, "V_MPEG4/ISO/AVC" ) )
2096             {
2097                 tracks[i_track]->fmt.i_codec = VLC_FOURCC( 'a', 'v', 'c', '1' );
2098                 tracks[i_track]->fmt.i_extra = tracks[i_track]->i_extra_data;
2099                 tracks[i_track]->fmt.p_extra = malloc( tracks[i_track]->i_extra_data );
2100                 memcpy( tracks[i_track]->fmt.p_extra,tracks[i_track]->p_extra_data, tracks[i_track]->i_extra_data );
2101             }
2102             else
2103             {
2104                 tracks[i_track]->fmt.i_codec = VLC_FOURCC( 'm', 'p', '4', 'v' );
2105             }
2106         }
2107         else if( !strcmp( tracks[i_track]->psz_codec, "V_QUICKTIME" ) )
2108         {
2109             MP4_Box_t *p_box = (MP4_Box_t*)malloc( sizeof( MP4_Box_t ) );
2110             stream_t *p_mp4_stream = stream_MemoryNew( VLC_OBJECT(&sys.demuxer),
2111                                                        tracks[i_track]->p_extra_data,
2112                                                        tracks[i_track]->i_extra_data,
2113                                                        VLC_FALSE );
2114             MP4_ReadBoxCommon( p_mp4_stream, p_box );
2115             MP4_ReadBox_sample_vide( p_mp4_stream, p_box );
2116             tracks[i_track]->fmt.i_codec = p_box->i_type;
2117             tracks[i_track]->fmt.video.i_width = p_box->data.p_sample_vide->i_width;
2118             tracks[i_track]->fmt.video.i_height = p_box->data.p_sample_vide->i_height;
2119             tracks[i_track]->fmt.i_extra = p_box->data.p_sample_vide->i_qt_image_description;
2120             tracks[i_track]->fmt.p_extra = malloc( tracks[i_track]->fmt.i_extra );
2121             memcpy( tracks[i_track]->fmt.p_extra, p_box->data.p_sample_vide->p_qt_image_description, tracks[i_track]->fmt.i_extra );
2122             MP4_FreeBox_sample_vide( p_box );
2123             stream_Delete( p_mp4_stream );
2124         }
2125         else if( !strcmp( tracks[i_track]->psz_codec, "A_MS/ACM" ) )
2126         {
2127             if( tracks[i_track]->i_extra_data < (int)sizeof( WAVEFORMATEX ) )
2128             {
2129                 msg_Err( &sys.demuxer, "missing/invalid WAVEFORMATEX" );
2130                 tracks[i_track]->fmt.i_codec = VLC_FOURCC( 'u', 'n', 'd', 'f' );
2131             }
2132             else
2133             {
2134                 WAVEFORMATEX *p_wf = (WAVEFORMATEX*)tracks[i_track]->p_extra_data;
2135
2136                 wf_tag_to_fourcc( GetWLE( &p_wf->wFormatTag ), &tracks[i_track]->fmt.i_codec, NULL );
2137
2138                 tracks[i_track]->fmt.audio.i_channels   = GetWLE( &p_wf->nChannels );
2139                 tracks[i_track]->fmt.audio.i_rate = GetDWLE( &p_wf->nSamplesPerSec );
2140                 tracks[i_track]->fmt.i_bitrate    = GetDWLE( &p_wf->nAvgBytesPerSec ) * 8;
2141                 tracks[i_track]->fmt.audio.i_blockalign = GetWLE( &p_wf->nBlockAlign );;
2142                 tracks[i_track]->fmt.audio.i_bitspersample = GetWLE( &p_wf->wBitsPerSample );
2143
2144                 tracks[i_track]->fmt.i_extra            = GetWLE( &p_wf->cbSize );
2145                 if( tracks[i_track]->fmt.i_extra > 0 )
2146                 {
2147                     tracks[i_track]->fmt.p_extra = malloc( tracks[i_track]->fmt.i_extra );
2148                     memcpy( tracks[i_track]->fmt.p_extra, &p_wf[1], tracks[i_track]->fmt.i_extra );
2149                 }
2150             }
2151         }
2152         else if( !strcmp( tracks[i_track]->psz_codec, "A_MPEG/L3" ) ||
2153                  !strcmp( tracks[i_track]->psz_codec, "A_MPEG/L2" ) ||
2154                  !strcmp( tracks[i_track]->psz_codec, "A_MPEG/L1" ) )
2155         {
2156             tracks[i_track]->fmt.i_codec = VLC_FOURCC( 'm', 'p', 'g', 'a' );
2157         }
2158         else if( !strcmp( tracks[i_track]->psz_codec, "A_AC3" ) )
2159         {
2160             tracks[i_track]->fmt.i_codec = VLC_FOURCC( 'a', '5', '2', ' ' );
2161         }
2162         else if( !strcmp( tracks[i_track]->psz_codec, "A_DTS" ) )
2163         {
2164             tracks[i_track]->fmt.i_codec = VLC_FOURCC( 'd', 't', 's', ' ' );
2165         }
2166         else if( !strcmp( tracks[i_track]->psz_codec, "A_FLAC" ) )
2167         {
2168             tracks[i_track]->fmt.i_codec = VLC_FOURCC( 'f', 'l', 'a', 'c' );
2169             tracks[i_track]->fmt.i_extra = tracks[i_track]->i_extra_data;
2170             tracks[i_track]->fmt.p_extra = malloc( tracks[i_track]->i_extra_data );
2171             memcpy( tracks[i_track]->fmt.p_extra,tracks[i_track]->p_extra_data, tracks[i_track]->i_extra_data );
2172         }
2173         else if( !strcmp( tracks[i_track]->psz_codec, "A_VORBIS" ) )
2174         {
2175             int i, i_offset = 1, i_size[3], i_extra;
2176             uint8_t *p_extra;
2177
2178             tracks[i_track]->fmt.i_codec = VLC_FOURCC( 'v', 'o', 'r', 'b' );
2179
2180             /* Split the 3 headers */
2181             if( tracks[i_track]->p_extra_data[0] != 0x02 )
2182                 msg_Err( &sys.demuxer, "invalid vorbis header" );
2183
2184             for( i = 0; i < 2; i++ )
2185             {
2186                 i_size[i] = 0;
2187                 while( i_offset < tracks[i_track]->i_extra_data )
2188                 {
2189                     i_size[i] += tracks[i_track]->p_extra_data[i_offset];
2190                     if( tracks[i_track]->p_extra_data[i_offset++] != 0xff ) break;
2191                 }
2192             }
2193
2194             i_size[0] = __MIN(i_size[0], tracks[i_track]->i_extra_data - i_offset);
2195             i_size[1] = __MIN(i_size[1], tracks[i_track]->i_extra_data -i_offset -i_size[0]);
2196             i_size[2] = tracks[i_track]->i_extra_data - i_offset - i_size[0] - i_size[1];
2197
2198             tracks[i_track]->fmt.i_extra = 3 * 2 + i_size[0] + i_size[1] + i_size[2];
2199             tracks[i_track]->fmt.p_extra = malloc( tracks[i_track]->fmt.i_extra );
2200             p_extra = (uint8_t *)tracks[i_track]->fmt.p_extra; i_extra = 0;
2201             for( i = 0; i < 3; i++ )
2202             {
2203                 *(p_extra++) = i_size[i] >> 8;
2204                 *(p_extra++) = i_size[i] & 0xFF;
2205                 memcpy( p_extra, tracks[i_track]->p_extra_data + i_offset + i_extra,
2206                         i_size[i] );
2207                 p_extra += i_size[i];
2208                 i_extra += i_size[i];
2209             }
2210         }
2211         else if( !strncmp( tracks[i_track]->psz_codec, "A_AAC/MPEG2/", strlen( "A_AAC/MPEG2/" ) ) ||
2212                  !strncmp( tracks[i_track]->psz_codec, "A_AAC/MPEG4/", strlen( "A_AAC/MPEG4/" ) ) )
2213         {
2214             int i_profile, i_srate;
2215             static unsigned int i_sample_rates[] =
2216             {
2217                     96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050,
2218                         16000, 12000, 11025, 8000,  7350,  0,     0,     0
2219             };
2220
2221             tracks[i_track]->fmt.i_codec = VLC_FOURCC( 'm', 'p', '4', 'a' );
2222             /* create data for faad (MP4DecSpecificDescrTag)*/
2223
2224             if( !strcmp( &tracks[i_track]->psz_codec[12], "MAIN" ) )
2225             {
2226                 i_profile = 0;
2227             }
2228             else if( !strcmp( &tracks[i_track]->psz_codec[12], "LC" ) )
2229             {
2230                 i_profile = 1;
2231             }
2232             else if( !strcmp( &tracks[i_track]->psz_codec[12], "SSR" ) )
2233             {
2234                 i_profile = 2;
2235             }
2236             else
2237             {
2238                 i_profile = 3;
2239             }
2240
2241             for( i_srate = 0; i_srate < 13; i_srate++ )
2242             {
2243                 if( i_sample_rates[i_srate] == tracks[i_track]->fmt.audio.i_rate )
2244                 {
2245                     break;
2246                 }
2247             }
2248             msg_Dbg( &sys.demuxer, "profile=%d srate=%d", i_profile, i_srate );
2249
2250             tracks[i_track]->fmt.i_extra = 2;
2251             tracks[i_track]->fmt.p_extra = malloc( tracks[i_track]->fmt.i_extra );
2252             ((uint8_t*)tracks[i_track]->fmt.p_extra)[0] = ((i_profile + 1) << 3) | ((i_srate&0xe) >> 1);
2253             ((uint8_t*)tracks[i_track]->fmt.p_extra)[1] = ((i_srate & 0x1) << 7) | (tracks[i_track]->fmt.audio.i_channels << 3);
2254         }
2255         else if( !strcmp( tracks[i_track]->psz_codec, "A_PCM/INT/BIG" ) ||
2256                  !strcmp( tracks[i_track]->psz_codec, "A_PCM/INT/LIT" ) ||
2257                  !strcmp( tracks[i_track]->psz_codec, "A_PCM/FLOAT/IEEE" ) )
2258         {
2259             if( !strcmp( tracks[i_track]->psz_codec, "A_PCM/INT/BIG" ) )
2260             {
2261                 tracks[i_track]->fmt.i_codec = VLC_FOURCC( 't', 'w', 'o', 's' );
2262             }
2263             else
2264             {
2265                 tracks[i_track]->fmt.i_codec = VLC_FOURCC( 'a', 'r', 'a', 'w' );
2266             }
2267             tracks[i_track]->fmt.audio.i_blockalign = ( tracks[i_track]->fmt.audio.i_bitspersample + 7 ) / 8 * tracks[i_track]->fmt.audio.i_channels;
2268         }
2269         else if( !strcmp( tracks[i_track]->psz_codec, "A_TTA1" ) )
2270         {
2271             /* FIXME: support this codec */
2272             msg_Err( &sys.demuxer, "TTA not supported yet[%d, n=%d]", (int)i_track, tracks[i_track]->i_number );
2273             tracks[i_track]->fmt.i_codec = VLC_FOURCC( 'u', 'n', 'd', 'f' );
2274         }
2275         else if( !strcmp( tracks[i_track]->psz_codec, "A_WAVPACK4" ) )
2276         {
2277             /* FIXME: support this codec */
2278             msg_Err( &sys.demuxer, "Wavpack not supported yet[%d, n=%d]", (int)i_track, tracks[i_track]->i_number );
2279             tracks[i_track]->fmt.i_codec = VLC_FOURCC( 'u', 'n', 'd', 'f' );
2280         }
2281         else if( !strcmp( tracks[i_track]->psz_codec, "S_TEXT/UTF8" ) )
2282         {
2283             tracks[i_track]->fmt.i_codec = VLC_FOURCC( 's', 'u', 'b', 't' );
2284             tracks[i_track]->fmt.subs.psz_encoding = strdup( "UTF-8" );
2285         }
2286         else if( !strcmp( tracks[i_track]->psz_codec, "S_TEXT/SSA" ) ||
2287                  !strcmp( tracks[i_track]->psz_codec, "S_TEXT/ASS" ) ||
2288                  !strcmp( tracks[i_track]->psz_codec, "S_SSA" ) ||
2289                  !strcmp( tracks[i_track]->psz_codec, "S_ASS" ))
2290         {
2291             tracks[i_track]->fmt.i_codec = VLC_FOURCC( 's', 's', 'a', ' ' );
2292             tracks[i_track]->fmt.subs.psz_encoding = strdup( "UTF-8" );
2293         }
2294         else if( !strcmp( tracks[i_track]->psz_codec, "S_VOBSUB" ) )
2295         {
2296             tracks[i_track]->fmt.i_codec = VLC_FOURCC( 's','p','u',' ' );
2297             if( tracks[i_track]->i_extra_data )
2298             {
2299                 char *p_start;
2300                 char *p_buf = (char *)malloc( tracks[i_track]->i_extra_data + 1);
2301                 memcpy( p_buf, tracks[i_track]->p_extra_data , tracks[i_track]->i_extra_data );
2302                 p_buf[tracks[i_track]->i_extra_data] = '\0';
2303                 
2304                 p_start = strstr( p_buf, "size:" );
2305                 if( sscanf( p_start, "size: %dx%d",
2306                         &tracks[i_track]->fmt.subs.spu.i_original_frame_width, &tracks[i_track]->fmt.subs.spu.i_original_frame_height ) == 2 )
2307                 {
2308                     msg_Dbg( &sys.demuxer, "original frame size vobsubs: %dx%d", tracks[i_track]->fmt.subs.spu.i_original_frame_width, tracks[i_track]->fmt.subs.spu.i_original_frame_height );
2309                 }
2310                 else
2311                 {
2312                     msg_Warn( &sys.demuxer, "reading original frame size for vobsub failed" );
2313                 }
2314                 free( p_buf );
2315             }
2316         }
2317         else if( !strcmp( tracks[i_track]->psz_codec, "B_VOBBTN" ) )
2318         {
2319             tracks[i_track]->fmt.i_cat = NAV_ES;
2320             continue;
2321         }
2322         else
2323         {
2324             msg_Err( &sys.demuxer, "unknow codec id=`%s'", tracks[i_track]->psz_codec );
2325             tracks[i_track]->fmt.i_codec = VLC_FOURCC( 'u', 'n', 'd', 'f' );
2326         }
2327         if( tracks[i_track]->b_default )
2328         {
2329             tracks[i_track]->fmt.i_priority = 1000;
2330         }
2331
2332         tracks[i_track]->p_es = es_out_Add( sys.demuxer.out, &tracks[i_track]->fmt );
2333
2334         es_out_Control( sys.demuxer.out, ES_OUT_SET_NEXT_DISPLAY_TIME, tracks[i_track]->p_es, i_start_time );
2335     }
2336     
2337     sys.i_start_pts = i_start_time;
2338     // reset the stream reading to the first cluster of the segment used
2339     es.I_O().setFilePointer( i_start_pos );
2340
2341     delete ep;
2342     ep = new EbmlParser( &es, segment, &sys.demuxer );
2343
2344     return true;
2345 }
2346
2347 void demux_sys_t::StartUiThread()
2348 {
2349     if ( !b_ui_hooked )
2350     {
2351         msg_Dbg( &demuxer, "Starting the UI Hook" );
2352         b_ui_hooked = true;
2353         /* FIXME hack hack hack hack FIXME */
2354         /* Get p_input and create variable */
2355         p_input = (input_thread_t *) vlc_object_find( &demuxer, VLC_OBJECT_INPUT, FIND_PARENT );
2356         var_Create( p_input, "x-start", VLC_VAR_INTEGER );
2357         var_Create( p_input, "y-start", VLC_VAR_INTEGER );
2358         var_Create( p_input, "x-end", VLC_VAR_INTEGER );
2359         var_Create( p_input, "y-end", VLC_VAR_INTEGER );
2360         var_Create( p_input, "color", VLC_VAR_ADDRESS );
2361         var_Create( p_input, "menu-palette", VLC_VAR_ADDRESS );
2362         var_Create( p_input, "highlight", VLC_VAR_BOOL );
2363         var_Create( p_input, "highlight-mutex", VLC_VAR_MUTEX );
2364
2365         /* Now create our event thread catcher */
2366         p_ev = (event_thread_t *) vlc_object_create( &demuxer, sizeof( event_thread_t ) );
2367         p_ev->p_demux = &demuxer;
2368         p_ev->b_die = VLC_FALSE;
2369         vlc_mutex_init( p_ev, &p_ev->lock );
2370         vlc_thread_create( p_ev, "mkv event thread handler", EventThread,
2371                         VLC_THREAD_PRIORITY_LOW, VLC_FALSE );
2372     }
2373 }
2374
2375 void demux_sys_t::StopUiThread()
2376 {
2377     if ( b_ui_hooked )
2378     {
2379         p_ev->b_die = VLC_TRUE;
2380
2381         vlc_thread_join( p_ev );
2382         vlc_object_destroy( p_ev );
2383
2384         p_ev = NULL;
2385
2386         var_Destroy( p_input, "highlight-mutex" );
2387         var_Destroy( p_input, "highlight" );
2388         var_Destroy( p_input, "x-start" );
2389         var_Destroy( p_input, "x-end" );
2390         var_Destroy( p_input, "y-start" );
2391         var_Destroy( p_input, "y-end" );
2392         var_Destroy( p_input, "color" );
2393         var_Destroy( p_input, "menu-palette" );
2394
2395         vlc_object_release( p_input );
2396
2397         msg_Dbg( &demuxer, "Stopping the UI Hook" );
2398     }
2399     b_ui_hooked = false;
2400 }
2401
2402 int demux_sys_t::EventMouse( vlc_object_t *p_this, char const *psz_var,
2403                        vlc_value_t oldval, vlc_value_t newval, void *p_data )
2404 {
2405     event_thread_t *p_ev = (event_thread_t *) p_data;
2406     vlc_mutex_lock( &p_ev->lock );
2407     if( psz_var[6] == 'c' )
2408         p_ev->b_clicked = VLC_TRUE;
2409     else if( psz_var[6] == 'm' )
2410         p_ev->b_moved = VLC_TRUE;
2411     vlc_mutex_unlock( &p_ev->lock );
2412
2413     return VLC_SUCCESS;
2414 }
2415
2416 int demux_sys_t::EventKey( vlc_object_t *p_this, char const *psz_var,
2417                      vlc_value_t oldval, vlc_value_t newval, void *p_data )
2418 {
2419     event_thread_t *p_ev = (event_thread_t *) p_data;
2420     vlc_mutex_lock( &p_ev->lock );
2421     p_ev->b_key = VLC_TRUE;
2422     vlc_mutex_unlock( &p_ev->lock );
2423
2424     return VLC_SUCCESS;
2425 }
2426
2427 int demux_sys_t::EventThread( vlc_object_t *p_this )
2428 {
2429     event_thread_t *p_ev = (event_thread_t*)p_this;
2430     demux_sys_t    *p_sys = p_ev->p_demux->p_sys;
2431     vlc_object_t   *p_vout = NULL;
2432
2433     p_ev->b_moved   = VLC_FALSE;
2434     p_ev->b_clicked = VLC_FALSE;
2435     p_ev->b_key     = VLC_FALSE;
2436
2437     /* catch all key event */
2438     var_AddCallback( p_ev->p_vlc, "key-pressed", EventKey, p_ev );
2439
2440     /* main loop */
2441     while( !p_ev->b_die )
2442     {
2443         if ( !p_sys->b_pci_packet_set )
2444         {
2445             /* Wait 100ms */
2446             msleep( 100000 );
2447             continue;
2448         }
2449
2450         vlc_bool_t b_activated = VLC_FALSE;
2451
2452         /* KEY part */
2453         if( p_ev->b_key )
2454         {
2455             vlc_value_t valk;
2456             struct vlc_t::hotkey *p_hotkeys = p_ev->p_vlc->p_hotkeys;
2457             int i, i_action = -1;
2458
2459             vlc_mutex_lock( &p_ev->lock );
2460
2461             pci_t *pci = (pci_t *) &p_sys->pci_packet;
2462
2463             var_Get( p_ev->p_vlc, "key-pressed", &valk );
2464             for( i = 0; p_hotkeys[i].psz_action != NULL; i++ )
2465             {
2466                 if( p_hotkeys[i].i_key == valk.i_int )
2467                 {
2468                     i_action = p_hotkeys[i].i_action;
2469                 }
2470             }
2471
2472             uint16 i_curr_button = p_sys->dvd_interpretor.GetSPRM( 0x88 );
2473
2474             switch( i_action )
2475             {
2476             case ACTIONID_NAV_LEFT:
2477                 if ( i_curr_button > 0 && i_curr_button <= pci->hli.hl_gi.btn_ns )
2478                 {
2479                     btni_t *p_button_ptr = &(pci->hli.btnit[i_curr_button-1]);
2480                     if ( p_button_ptr->left > 0 && p_button_ptr->left <= pci->hli.hl_gi.btn_ns )
2481                     {
2482                         i_curr_button = p_button_ptr->left;
2483                         p_sys->dvd_interpretor.SetSPRM( 0x88, i_curr_button );
2484                         btni_t button_ptr = pci->hli.btnit[i_curr_button-1];
2485                         if ( button_ptr.auto_action_mode )
2486                         {
2487                             vlc_mutex_unlock( &p_ev->lock );
2488                             vlc_mutex_lock( &p_sys->lock_demuxer );
2489
2490                             // process the button action
2491                             p_sys->dvd_interpretor.Interpret( button_ptr.cmd.bytes, 8 );
2492
2493                             vlc_mutex_unlock( &p_sys->lock_demuxer );
2494                             vlc_mutex_lock( &p_ev->lock );
2495                         }
2496                     }
2497                 }
2498                 break;
2499             case ACTIONID_NAV_RIGHT:
2500                 if ( i_curr_button > 0 && i_curr_button <= pci->hli.hl_gi.btn_ns )
2501                 {
2502                     btni_t *p_button_ptr = &(pci->hli.btnit[i_curr_button-1]);
2503                     if ( p_button_ptr->right > 0 && p_button_ptr->right <= pci->hli.hl_gi.btn_ns )
2504                     {
2505                         i_curr_button = p_button_ptr->right;
2506                         p_sys->dvd_interpretor.SetSPRM( 0x88, i_curr_button );
2507                         btni_t button_ptr = pci->hli.btnit[i_curr_button-1];
2508                         if ( button_ptr.auto_action_mode )
2509                         {
2510                             vlc_mutex_unlock( &p_ev->lock );
2511                             vlc_mutex_lock( &p_sys->lock_demuxer );
2512
2513                             // process the button action
2514                             p_sys->dvd_interpretor.Interpret( button_ptr.cmd.bytes, 8 );
2515
2516                             vlc_mutex_unlock( &p_sys->lock_demuxer );
2517                             vlc_mutex_lock( &p_ev->lock );
2518                         }
2519                     }
2520                 }
2521                 break;
2522             case ACTIONID_NAV_UP:
2523                 if ( i_curr_button > 0 && i_curr_button <= pci->hli.hl_gi.btn_ns )
2524                 {
2525                     btni_t *p_button_ptr = &(pci->hli.btnit[i_curr_button-1]);
2526                     if ( p_button_ptr->up > 0 && p_button_ptr->up <= pci->hli.hl_gi.btn_ns )
2527                     {
2528                         i_curr_button = p_button_ptr->up;
2529                         p_sys->dvd_interpretor.SetSPRM( 0x88, i_curr_button );
2530                         btni_t button_ptr = pci->hli.btnit[i_curr_button-1];
2531                         if ( button_ptr.auto_action_mode )
2532                         {
2533                             vlc_mutex_unlock( &p_ev->lock );
2534                             vlc_mutex_lock( &p_sys->lock_demuxer );
2535
2536                             // process the button action
2537                             p_sys->dvd_interpretor.Interpret( button_ptr.cmd.bytes, 8 );
2538
2539                             vlc_mutex_unlock( &p_sys->lock_demuxer );
2540                             vlc_mutex_lock( &p_ev->lock );
2541                         }
2542                     }
2543                 }
2544                 break;
2545             case ACTIONID_NAV_DOWN:
2546                 if ( i_curr_button > 0 && i_curr_button <= pci->hli.hl_gi.btn_ns )
2547                 {
2548                     btni_t *p_button_ptr = &(pci->hli.btnit[i_curr_button-1]);
2549                     if ( p_button_ptr->down > 0 && p_button_ptr->down <= pci->hli.hl_gi.btn_ns )
2550                     {
2551                         i_curr_button = p_button_ptr->down;
2552                         p_sys->dvd_interpretor.SetSPRM( 0x88, i_curr_button );
2553                         btni_t button_ptr = pci->hli.btnit[i_curr_button-1];
2554                         if ( button_ptr.auto_action_mode )
2555                         {
2556                             vlc_mutex_unlock( &p_ev->lock );
2557                             vlc_mutex_lock( &p_sys->lock_demuxer );
2558
2559                             // process the button action
2560                             p_sys->dvd_interpretor.Interpret( button_ptr.cmd.bytes, 8 );
2561
2562                             vlc_mutex_unlock( &p_sys->lock_demuxer );
2563                             vlc_mutex_lock( &p_ev->lock );
2564                         }
2565                     }
2566                 }
2567                 break;
2568             case ACTIONID_NAV_ACTIVATE:
2569                 b_activated = VLC_TRUE;
2570         
2571                 if ( i_curr_button > 0 && i_curr_button <= pci->hli.hl_gi.btn_ns )
2572                 {
2573                     btni_t button_ptr = pci->hli.btnit[i_curr_button-1];
2574
2575                     vlc_mutex_unlock( &p_ev->lock );
2576                     vlc_mutex_lock( &p_sys->lock_demuxer );
2577
2578                     // process the button action
2579                     p_sys->dvd_interpretor.Interpret( button_ptr.cmd.bytes, 8 );
2580
2581                     vlc_mutex_unlock( &p_sys->lock_demuxer );
2582                     vlc_mutex_lock( &p_ev->lock );
2583                 }
2584                 break;
2585             default:
2586                 break;
2587             }
2588             p_ev->b_key = VLC_FALSE;
2589             vlc_mutex_unlock( &p_ev->lock );
2590         }
2591
2592         /* MOUSE part */
2593         if( p_vout && ( p_ev->b_moved || p_ev->b_clicked ) )
2594         {
2595             vlc_value_t valx, valy;
2596
2597             vlc_mutex_lock( &p_ev->lock );
2598             pci_t *pci = (pci_t *) &p_sys->pci_packet;
2599             var_Get( p_vout, "mouse-x", &valx );
2600             var_Get( p_vout, "mouse-y", &valy );
2601
2602             if( p_ev->b_clicked )
2603             {
2604                 int32_t button;
2605                 int32_t best,dist,d;
2606                 int32_t mx,my,dx,dy;
2607
2608                 b_activated = VLC_TRUE;
2609                 // get current button
2610                 best = 0;
2611                 dist = 0x08000000; /* >> than  (720*720)+(567*567); */
2612                 for(button = 1; button <= pci->hli.hl_gi.btn_ns; button++) 
2613                 {
2614                     btni_t *button_ptr = &(pci->hli.btnit[button-1]);
2615
2616                     if(((unsigned)valx.i_int >= button_ptr->x_start)
2617                      && ((unsigned)valx.i_int <= button_ptr->x_end)
2618                      && ((unsigned)valy.i_int >= button_ptr->y_start)
2619                      && ((unsigned)valy.i_int <= button_ptr->y_end)) 
2620                     {
2621                         mx = (button_ptr->x_start + button_ptr->x_end)/2;
2622                         my = (button_ptr->y_start + button_ptr->y_end)/2;
2623                         dx = mx - valx.i_int;
2624                         dy = my - valy.i_int;
2625                         d = (dx*dx) + (dy*dy);
2626                         /* If the mouse is within the button and the mouse is closer
2627                         * to the center of this button then it is the best choice. */
2628                         if(d < dist) {
2629                             dist = d;
2630                             best = button;
2631                         }
2632                     }
2633                 }
2634
2635                 if ( best != 0)
2636                 {
2637                     btni_t button_ptr = pci->hli.btnit[best-1];
2638                     uint16 i_curr_button = p_sys->dvd_interpretor.GetSPRM( 0x88 );
2639
2640                     msg_Dbg( &p_sys->demuxer, "Clicked button %d", best );
2641                     vlc_mutex_unlock( &p_ev->lock );
2642                     vlc_mutex_lock( &p_sys->lock_demuxer );
2643
2644                     // process the button action
2645                     p_sys->dvd_interpretor.SetSPRM( 0x88, best );
2646                     p_sys->dvd_interpretor.Interpret( button_ptr.cmd.bytes, 8 );
2647
2648                     msg_Dbg( &p_sys->demuxer, "Processed button %d", best );
2649
2650                     // select new button
2651                     if ( best != i_curr_button )
2652                     {
2653                         vlc_value_t val;
2654
2655                         if( var_Get( p_sys->p_input, "highlight-mutex", &val ) == VLC_SUCCESS )
2656                         {
2657                             vlc_mutex_t *p_mutex = (vlc_mutex_t *) val.p_address;
2658                             uint32_t i_palette;
2659
2660                             if(button_ptr.btn_coln != 0) {
2661                                 i_palette = pci->hli.btn_colit.btn_coli[button_ptr.btn_coln-1][1];
2662                             } else {
2663                                 i_palette = 0;
2664                             }
2665
2666                             for( int i = 0; i < 4; i++ )
2667                             {
2668                                 uint32_t i_yuv = 0xFF;//p_sys->clut[(hl.palette>>(16+i*4))&0x0f];
2669                                 uint8_t i_alpha = (i_palette>>(i*4))&0x0f;
2670                                 i_alpha = i_alpha == 0xf ? 0xff : i_alpha << 4;
2671
2672                                 p_sys->palette[i][0] = (i_yuv >> 16) & 0xff;
2673                                 p_sys->palette[i][1] = (i_yuv >> 0) & 0xff;
2674                                 p_sys->palette[i][2] = (i_yuv >> 8) & 0xff;
2675                                 p_sys->palette[i][3] = i_alpha;
2676                             }
2677
2678                             vlc_mutex_lock( p_mutex );
2679                             val.i_int = button_ptr.x_start; var_Set( p_sys->p_input, "x-start", val );
2680                             val.i_int = button_ptr.x_end;   var_Set( p_sys->p_input, "x-end",   val );
2681                             val.i_int = button_ptr.y_start; var_Set( p_sys->p_input, "y-start", val );
2682                             val.i_int = button_ptr.y_end;   var_Set( p_sys->p_input, "y-end",   val );
2683
2684                             val.p_address = (void *)p_sys->palette;
2685                             var_Set( p_sys->p_input, "menu-palette", val );
2686
2687                             val.b_bool = VLC_TRUE; var_Set( p_sys->p_input, "highlight", val );
2688                             vlc_mutex_unlock( p_mutex );
2689                         }
2690                     }
2691                     vlc_mutex_unlock( &p_sys->lock_demuxer );
2692                     vlc_mutex_lock( &p_ev->lock );
2693                 }
2694             }
2695             else if( p_ev->b_moved )
2696             {
2697 //                dvdnav_mouse_select( NULL, pci, valx.i_int, valy.i_int );
2698             }
2699
2700             p_ev->b_moved = VLC_FALSE;
2701             p_ev->b_clicked = VLC_FALSE;
2702             vlc_mutex_unlock( &p_ev->lock );
2703         }
2704
2705         /* VOUT part */
2706         if( p_vout && p_vout->b_die )
2707         {
2708             var_DelCallback( p_vout, "mouse-moved", EventMouse, p_ev );
2709             var_DelCallback( p_vout, "mouse-clicked", EventMouse, p_ev );
2710             vlc_object_release( p_vout );
2711             p_vout = NULL;
2712         }
2713
2714         else if( p_vout == NULL )
2715         {
2716             p_vout = (vlc_object_t*) vlc_object_find( p_sys->p_input, VLC_OBJECT_VOUT,
2717                                       FIND_CHILD );
2718             if( p_vout)
2719             {
2720                 var_AddCallback( p_vout, "mouse-moved", EventMouse, p_ev );
2721                 var_AddCallback( p_vout, "mouse-clicked", EventMouse, p_ev );
2722             }
2723         }
2724
2725         /* Wait a bit, 10ms */
2726         msleep( 10000 );
2727     }
2728
2729     /* Release callback */
2730     if( p_vout )
2731     {
2732         var_DelCallback( p_vout, "mouse-moved", EventMouse, p_ev );
2733         var_DelCallback( p_vout, "mouse-clicked", EventMouse, p_ev );
2734         vlc_object_release( p_vout );
2735     }
2736     var_DelCallback( p_ev->p_vlc, "key-pressed", EventKey, p_ev );
2737
2738     vlc_mutex_destroy( &p_ev->lock );
2739
2740     return VLC_SUCCESS;
2741 }
2742
2743 void matroska_segment_c::UnSelect( )
2744 {
2745     size_t i_track;
2746
2747     for( i_track = 0; i_track < tracks.size(); i_track++ )
2748     {
2749         if ( tracks[i_track]->p_es != NULL )
2750         {
2751 //            es_format_Clean( &tracks[i_track]->fmt );
2752             es_out_Del( sys.demuxer.out, tracks[i_track]->p_es );
2753             tracks[i_track]->p_es = NULL;
2754         }
2755     }
2756     delete ep;
2757     ep = NULL;
2758 }
2759
2760 void virtual_segment_c::PrepareChapters( )
2761 {
2762     if ( linked_segments.size() == 0 )
2763         return;
2764
2765     // !!! should be called only once !!!
2766     matroska_segment_c *p_segment;
2767     size_t i, j;
2768
2769     // copy editions from the first segment
2770     p_segment = linked_segments[0];
2771     p_editions = &p_segment->stored_editions;
2772
2773     for ( i=1 ; i<linked_segments.size(); i++ )
2774     {
2775         p_segment = linked_segments[i];
2776         // FIXME assume we have the same editions in all segments
2777         for (j=0; j<p_segment->stored_editions.size(); j++)
2778             (*p_editions)[j]->Append( *p_segment->stored_editions[j] );
2779     }
2780 }
2781
2782 std::string chapter_edition_c::GetMainName() const
2783 {
2784     if ( sub_chapters.size() )
2785     {
2786         return sub_chapters[0]->GetCodecName( true );
2787     }
2788     return "";
2789 }
2790
2791 int chapter_item_c::PublishChapters( input_title_t & title, int & i_user_chapters, int i_level )
2792 {
2793     // add support for meta-elements from codec like DVD Titles
2794     if ( !b_display_seekpoint || psz_name == "" )
2795     {
2796         psz_name = GetCodecName();
2797         if ( psz_name != "" )
2798             b_display_seekpoint = true;
2799     }
2800
2801     if (b_display_seekpoint)
2802     {
2803         seekpoint_t *sk = vlc_seekpoint_New();
2804
2805         sk->i_level = i_level;
2806         sk->i_time_offset = i_start_time;
2807         sk->psz_name = strdup( psz_name.c_str() );
2808
2809         // A start time of '0' is ok. A missing ChapterTime element is ok, too, because '0' is its default value.
2810         title.i_seekpoint++;
2811         title.seekpoint = (seekpoint_t**)realloc( title.seekpoint, title.i_seekpoint * sizeof( seekpoint_t* ) );
2812         title.seekpoint[title.i_seekpoint-1] = sk;
2813
2814         if ( b_user_display )
2815             i_user_chapters++;
2816     }
2817
2818     for ( size_t i=0; i<sub_chapters.size() ; i++)
2819     {
2820         sub_chapters[i]->PublishChapters( title, i_user_chapters, i_level+1 );
2821     }
2822
2823     i_seekpoint_num = i_user_chapters;
2824
2825     return i_user_chapters;
2826 }
2827
2828 bool virtual_segment_c::UpdateCurrentToChapter( demux_t & demux )
2829 {
2830     demux_sys_t & sys = *demux.p_sys;
2831     chapter_item_c *psz_curr_chapter;
2832     bool b_has_seeked = false;
2833
2834     /* update current chapter/seekpoint */
2835     if ( p_editions->size() )
2836     {
2837         /* 1st, we need to know in which chapter we are */
2838         psz_curr_chapter = (*p_editions)[i_current_edition]->FindTimecode( sys.i_pts, psz_current_chapter );
2839
2840         /* we have moved to a new chapter */
2841         if (psz_curr_chapter != NULL && psz_current_chapter != psz_curr_chapter)
2842         {
2843             if ( (*p_editions)[i_current_edition]->b_ordered )
2844             {
2845                 // Leave/Enter up to the link point
2846                 b_has_seeked = psz_curr_chapter->EnterAndLeave( psz_current_chapter );
2847                 if ( !b_has_seeked )
2848                 {
2849                     // only physically seek if necessary
2850                     if ( psz_current_chapter == NULL || (psz_current_chapter->i_end_time != psz_curr_chapter->i_start_time) )
2851                         Seek( demux, sys.i_pts, 0, psz_curr_chapter );
2852                 }
2853             }
2854             
2855             if ( !b_has_seeked )
2856             {
2857                 psz_current_chapter = psz_curr_chapter;
2858                 if ( psz_curr_chapter->i_seekpoint_num > 0 )
2859                 {
2860                     demux.info.i_update |= INPUT_UPDATE_TITLE | INPUT_UPDATE_SEEKPOINT;
2861                     demux.info.i_title = sys.i_current_title = i_sys_title;
2862                     demux.info.i_seekpoint = psz_curr_chapter->i_seekpoint_num - 1;
2863                 }
2864             }
2865
2866             return true;
2867         }
2868         else if (psz_curr_chapter == NULL)
2869         {
2870             // out of the scope of the data described by chapters, leave the edition
2871             if ( (*p_editions)[i_current_edition]->b_ordered && psz_current_chapter != NULL )
2872             {
2873                 if ( !(*p_editions)[i_current_edition]->EnterAndLeave( psz_current_chapter, false ) )
2874                     psz_current_chapter = NULL;
2875                 else
2876                     return true;
2877             }
2878         }
2879     }
2880     return false;
2881 }
2882
2883 chapter_item_c *virtual_segment_c::BrowseCodecPrivate( unsigned int codec_id, 
2884                                     bool (*match)(const chapter_codec_cmds_c &data, const void *p_cookie, size_t i_cookie_size ), 
2885                                     const void *p_cookie, 
2886                                     size_t i_cookie_size )
2887 {
2888     // FIXME don't assume it is the first edition
2889     std::vector<chapter_edition_c*>::iterator index = p_editions->begin();
2890     if ( index != p_editions->end() )
2891     {
2892         chapter_item_c *p_result = (*index)->BrowseCodecPrivate( codec_id, match, p_cookie, i_cookie_size );
2893         if ( p_result != NULL )
2894             return p_result;
2895     }
2896     return NULL;
2897 }
2898
2899 chapter_item_c *virtual_segment_c::FindChapter( int64_t i_find_uid )
2900 {
2901     // FIXME don't assume it is the first edition
2902     std::vector<chapter_edition_c*>::iterator index = p_editions->begin();
2903     if ( index != p_editions->end() )
2904     {
2905         chapter_item_c *p_result = (*index)->FindChapter( i_find_uid );
2906         if ( p_result != NULL )
2907             return p_result;
2908     }
2909     return NULL;
2910 }
2911
2912 chapter_item_c *chapter_item_c::BrowseCodecPrivate( unsigned int codec_id, 
2913                                     bool (*match)(const chapter_codec_cmds_c &data, const void *p_cookie, size_t i_cookie_size ), 
2914                                     const void *p_cookie, 
2915                                     size_t i_cookie_size )
2916 {
2917     // this chapter
2918     std::vector<chapter_codec_cmds_c*>::const_iterator index = codecs.begin();
2919     while ( index != codecs.end() )
2920     {
2921         if ( match( **index ,p_cookie, i_cookie_size ) )
2922             return this;
2923         index++;
2924     }
2925     
2926     // sub-chapters
2927     chapter_item_c *p_result = NULL;
2928     std::vector<chapter_item_c*>::const_iterator index2 = sub_chapters.begin();
2929     while ( index2 != sub_chapters.end() )
2930     {
2931         p_result = (*index2)->BrowseCodecPrivate( codec_id, match, p_cookie, i_cookie_size );
2932         if ( p_result != NULL )
2933             return p_result;
2934         index2++;
2935     }
2936     
2937     return p_result;
2938 }
2939
2940 void chapter_item_c::Append( const chapter_item_c & chapter )
2941 {
2942     // we are appending content for the same chapter UID
2943     size_t i;
2944     chapter_item_c *p_chapter;
2945
2946     for ( i=0; i<chapter.sub_chapters.size(); i++ )
2947     {
2948         p_chapter = FindChapter( chapter.sub_chapters[i]->i_uid );
2949         if ( p_chapter != NULL )
2950         {
2951             p_chapter->Append( *chapter.sub_chapters[i] );
2952         }
2953         else
2954         {
2955             sub_chapters.push_back( chapter.sub_chapters[i] );
2956         }
2957     }
2958
2959     i_user_start_time = min( i_user_start_time, chapter.i_user_start_time );
2960     i_user_end_time = max( i_user_end_time, chapter.i_user_end_time );
2961 }
2962
2963 chapter_item_c * chapter_item_c::FindChapter( int64_t i_find_uid )
2964 {
2965     size_t i;
2966     chapter_item_c *p_result = NULL;
2967
2968     if ( i_uid == i_find_uid )
2969         return this;
2970
2971     for ( i=0; i<sub_chapters.size(); i++)
2972     {
2973         p_result = sub_chapters[i]->FindChapter( i_find_uid );
2974         if ( p_result != NULL )
2975             break;
2976     }
2977     return p_result;
2978 }
2979
2980 std::string chapter_item_c::GetCodecName( bool f_for_title ) const
2981 {
2982     std::string result;
2983
2984     std::vector<chapter_codec_cmds_c*>::const_iterator index = codecs.begin();
2985     while ( index != codecs.end() )
2986     {
2987         result = (*index)->GetCodecName( f_for_title );
2988         if ( result != "" )
2989             break;
2990         index++;
2991     }
2992
2993     return result;
2994 }
2995
2996 std::string dvd_chapter_codec_c::GetCodecName( bool f_for_title ) const
2997 {
2998     std::string result;
2999     if ( p_private_data->GetSize() >= 3)
3000     {
3001         const binary* p_data = p_private_data->GetBuffer();
3002 /*        if ( p_data[0] == MATROSKA_DVD_LEVEL_TT )
3003         {
3004             uint16_t i_title = (p_data[1] << 8) + p_data[2];
3005             char psz_str[11];
3006             sprintf( psz_str, " %d  ---", i_title );
3007             result = N_("---  DVD Title");
3008             result += psz_str;
3009         }
3010         else */ if ( p_data[0] == MATROSKA_DVD_LEVEL_LU )
3011         {
3012             char psz_str[11];
3013             sprintf( psz_str, " (%c%c)  ---", p_data[1], p_data[2] );
3014             result = N_("---  DVD Menu");
3015             result += psz_str;
3016         }
3017         else if ( p_data[0] == MATROSKA_DVD_LEVEL_SS && f_for_title )
3018         {
3019             if ( p_data[1] == 0x00 )
3020                 result = N_("First Played");
3021             else if ( p_data[1] == 0xC0 )
3022                 result = N_("Video Manager");
3023             else if ( p_data[1] == 0x80 )
3024             {
3025                 uint16_t i_title = (p_data[2] << 8) + p_data[3];
3026                 char psz_str[20];
3027                 sprintf( psz_str, " %d -----", i_title );
3028                 result = N_("----- Title");
3029                 result += psz_str;
3030             }
3031         }
3032     }
3033
3034     return result;
3035 }
3036
3037 int16 chapter_item_c::GetTitleNumber( ) const
3038 {
3039     int result = -1;
3040
3041     std::vector<chapter_codec_cmds_c*>::const_iterator index = codecs.begin();
3042     while ( index != codecs.end() )
3043     {
3044         result = (*index)->GetTitleNumber( );
3045         if ( result >= 0 )
3046             break;
3047         index++;
3048     }
3049
3050     return result;
3051 }
3052
3053 int16 dvd_chapter_codec_c::GetTitleNumber()
3054 {
3055     if ( p_private_data->GetSize() >= 3)
3056     {
3057         const binary* p_data = p_private_data->GetBuffer();
3058         if ( p_data[0] == MATROSKA_DVD_LEVEL_SS )
3059         {
3060             return int16( (p_data[2] << 8) + p_data[3] );
3061         }
3062     }
3063     return -1;
3064 }
3065
3066 static void Seek( demux_t *p_demux, mtime_t i_date, double f_percent, chapter_item_c *psz_chapter )
3067 {
3068     demux_sys_t        *p_sys = p_demux->p_sys;
3069     virtual_segment_c  *p_vsegment = p_sys->p_current_segment;
3070     matroska_segment_c *p_segment = p_vsegment->Segment();
3071     mtime_t            i_time_offset = 0;
3072
3073     int         i_index;
3074
3075     msg_Dbg( p_demux, "seek request to "I64Fd" (%f%%)", i_date, f_percent );
3076     if( i_date < 0 && f_percent < 0 )
3077     {
3078         msg_Warn( p_demux, "cannot seek nowhere !" );
3079         return;
3080     }
3081     if( f_percent > 1.0 )
3082     {
3083         msg_Warn( p_demux, "cannot seek so far !" );
3084         return;
3085     }
3086
3087     /* seek without index or without date */
3088     if( f_percent >= 0 && (config_GetInt( p_demux, "mkv-seek-percent" ) || !p_segment->b_cues || i_date < 0 ))
3089     {
3090         if (p_sys->f_duration >= 0)
3091         {
3092             i_date = int64_t( f_percent * p_sys->f_duration * 1000.0 );
3093         }
3094         else
3095         {
3096             int64_t i_pos = int64_t( f_percent * stream_Size( p_demux->s ) );
3097
3098             msg_Dbg( p_demux, "inacurate way of seeking" );
3099             for( i_index = 0; i_index < p_segment->i_index; i_index++ )
3100             {
3101                 if( p_segment->p_indexes[i_index].i_position >= i_pos)
3102                 {
3103                     break;
3104                 }
3105             }
3106             if( i_index == p_segment->i_index )
3107             {
3108                 i_index--;
3109             }
3110
3111             i_date = p_segment->p_indexes[i_index].i_time;
3112
3113 #if 0
3114             if( p_segment->p_indexes[i_index].i_position < i_pos )
3115             {
3116                 EbmlElement *el;
3117
3118                 msg_Warn( p_demux, "searching for cluster, could take some time" );
3119
3120                 /* search a cluster */
3121                 while( ( el = p_sys->ep->Get() ) != NULL )
3122                 {
3123                     if( MKV_IS_ID( el, KaxCluster ) )
3124                     {
3125                         KaxCluster *cluster = (KaxCluster*)el;
3126
3127                         /* add it to the index */
3128                         p_segment->IndexAppendCluster( cluster );
3129
3130                         if( (int64_t)cluster->GetElementPosition() >= i_pos )
3131                         {
3132                             p_sys->cluster = cluster;
3133                             p_sys->ep->Down();
3134                             break;
3135                         }
3136                     }
3137                 }
3138             }
3139 #endif
3140         }
3141     }
3142
3143     p_vsegment->Seek( *p_demux, i_date, i_time_offset, psz_chapter );
3144 }
3145
3146 /*****************************************************************************
3147  * Demux: reads and demuxes data packets
3148  *****************************************************************************
3149  * Returns -1 in case of error, 0 in case of EOF, 1 otherwise
3150  *****************************************************************************/
3151 static int Demux( demux_t *p_demux)
3152 {
3153     demux_sys_t        *p_sys = p_demux->p_sys;
3154
3155     vlc_mutex_lock( &p_sys->lock_demuxer );
3156
3157     virtual_segment_c  *p_vsegment = p_sys->p_current_segment;
3158     matroska_segment_c *p_segment = p_vsegment->Segment();
3159     if ( p_segment == NULL ) return 0;
3160     int                i_block_count = 0;
3161     int                i_return = 0;
3162
3163     for( ;; )
3164     {
3165         if ( p_sys->demuxer.b_die )
3166             break;
3167
3168         if( p_sys->i_pts >= p_sys->i_start_pts  )
3169             if ( p_vsegment->UpdateCurrentToChapter( *p_demux ) )
3170             {
3171                 i_return = 1;
3172                 break;
3173             }
3174         
3175         if ( p_vsegment->Edition() && p_vsegment->Edition()->b_ordered && p_vsegment->CurrentChapter() == NULL )
3176         {
3177             /* nothing left to read in this ordered edition */
3178             if ( !p_vsegment->SelectNext() )
3179                 break;
3180             p_segment->UnSelect( );
3181             
3182             es_out_Control( p_demux->out, ES_OUT_RESET_PCR );
3183
3184             /* switch to the next segment */
3185             p_segment = p_vsegment->Segment();
3186             if ( !p_segment->Select( 0 ) )
3187             {
3188                 msg_Err( p_demux, "Failed to select new segment" );
3189                 break;
3190             }
3191             continue;
3192         }
3193
3194         KaxBlock *block;
3195         int64_t i_block_duration = 0;
3196         int64_t i_block_ref1;
3197         int64_t i_block_ref2;
3198
3199         if( p_segment->BlockGet( block, &i_block_ref1, &i_block_ref2, &i_block_duration ) )
3200         {
3201             if ( p_vsegment->Edition() && p_vsegment->Edition()->b_ordered )
3202             {
3203                 const chapter_item_c *p_chap = p_vsegment->CurrentChapter();
3204                 // check if there are more chapters to read
3205                 if ( p_chap != NULL )
3206                 {
3207                     /* TODO handle successive chapters with the same user_start_time/user_end_time
3208                     if ( p_chap->i_user_start_time == p_chap->i_user_start_time )
3209                         p_vsegment->SelectNext();
3210                     */
3211                     p_sys->i_pts = p_chap->i_user_end_time;
3212                     p_sys->i_pts++; // trick to avoid staying on segments with no duration and no content
3213
3214                     i_return = 1;
3215                 }
3216
3217                 break;
3218             }
3219             else
3220             {
3221                 msg_Warn( p_demux, "cannot get block EOF?" );
3222                 p_segment->UnSelect( );
3223                 
3224                 es_out_Control( p_demux->out, ES_OUT_RESET_PCR );
3225
3226                 /* switch to the next segment */
3227                 if ( !p_vsegment->SelectNext() )
3228                     // no more segments in this stream
3229                     break;
3230                 p_segment = p_vsegment->Segment();
3231                 if ( !p_segment->Select( 0 ) )
3232                 {
3233                     msg_Err( p_demux, "Failed to select new segment" );
3234                     break;
3235                 }
3236
3237                 continue;
3238             }
3239         }
3240
3241         p_sys->i_pts = (p_sys->i_chapter_time + block->GlobalTimecode()) / (mtime_t) 1000;
3242
3243         if( p_sys->i_pts >= p_sys->i_start_pts  )
3244             if ( p_vsegment->UpdateCurrentToChapter( *p_demux ) )
3245             {
3246                 i_return = 1;
3247                 delete block;
3248                 break;
3249             }
3250         
3251         if ( p_vsegment->Edition() && p_vsegment->Edition()->b_ordered && p_vsegment->CurrentChapter() == NULL )
3252         {
3253             /* nothing left to read in this ordered edition */
3254             if ( !p_vsegment->SelectNext() )
3255             {
3256                 delete block;
3257                 break;
3258             }
3259             p_segment->UnSelect( );
3260             
3261             es_out_Control( p_demux->out, ES_OUT_RESET_PCR );
3262
3263             /* switch to the next segment */
3264             p_segment = p_vsegment->Segment();
3265             if ( !p_segment->Select( 0 ) )
3266             {
3267                 msg_Err( p_demux, "Failed to select new segment" );
3268                 delete block;
3269                 break;
3270             }
3271             delete block;
3272             continue;
3273         }
3274
3275         BlockDecode( p_demux, block, p_sys->i_pts, i_block_duration, i_block_ref1 >= 0 || i_block_ref2 > 0 );
3276
3277         delete block;
3278         i_block_count++;
3279
3280         // TODO optimize when there is need to leave or when seeking has been called
3281         if( i_block_count > 5 )
3282         {
3283             i_return = 1;
3284             break;
3285         }
3286     }
3287
3288     vlc_mutex_unlock( &p_sys->lock_demuxer );
3289
3290     return i_return;
3291 }
3292
3293
3294
3295 /*****************************************************************************
3296  * Stream managment
3297  *****************************************************************************/
3298 vlc_stream_io_callback::vlc_stream_io_callback( stream_t *s_, vlc_bool_t b_owner_ )
3299 {
3300     s = s_;
3301     b_owner = b_owner_;
3302     mb_eof = VLC_FALSE;
3303 }
3304
3305 uint32 vlc_stream_io_callback::read( void *p_buffer, size_t i_size )
3306 {
3307     if( i_size <= 0 || mb_eof )
3308     {
3309         return 0;
3310     }
3311
3312     return stream_Read( s, p_buffer, i_size );
3313 }
3314 void vlc_stream_io_callback::setFilePointer(int64_t i_offset, seek_mode mode )
3315 {
3316     int64_t i_pos;
3317
3318     switch( mode )
3319     {
3320         case seek_beginning:
3321             i_pos = i_offset;
3322             break;
3323         case seek_end:
3324             i_pos = stream_Size( s ) - i_offset;
3325             break;
3326         default:
3327             i_pos= stream_Tell( s ) + i_offset;
3328             break;
3329     }
3330
3331     if( i_pos < 0 || i_pos >= stream_Size( s ) )
3332     {
3333         mb_eof = VLC_TRUE;
3334         return;
3335     }
3336
3337     mb_eof = VLC_FALSE;
3338     if( stream_Seek( s, i_pos ) )
3339     {
3340         mb_eof = VLC_TRUE;
3341     }
3342     return;
3343 }
3344 size_t vlc_stream_io_callback::write( const void *p_buffer, size_t i_size )
3345 {
3346     return 0;
3347 }
3348 uint64 vlc_stream_io_callback::getFilePointer( void )
3349 {
3350     if ( s == NULL )
3351         return 0;
3352     return stream_Tell( s );
3353 }
3354 void vlc_stream_io_callback::close( void )
3355 {
3356     return;
3357 }
3358
3359
3360 /*****************************************************************************
3361  * Ebml Stream parser
3362  *****************************************************************************/
3363 EbmlParser::EbmlParser( EbmlStream *es, EbmlElement *el_start, demux_t *p_demux )
3364 {
3365     int i;
3366
3367     m_es = es;
3368     m_got = NULL;
3369     m_el[0] = el_start;
3370     mi_remain_size[0] = el_start->GetSize();
3371
3372     for( i = 1; i < 6; i++ )
3373     {
3374         m_el[i] = NULL;
3375     }
3376     mi_level = 1;
3377     mi_user_level = 1;
3378     mb_keep = VLC_FALSE;
3379     mb_dummy = config_GetInt( p_demux, "mkv-use-dummy" );
3380 }
3381
3382 EbmlParser::~EbmlParser( void )
3383 {
3384     int i;
3385
3386     for( i = 1; i < mi_level; i++ )
3387     {
3388         if( !mb_keep )
3389         {
3390             delete m_el[i];
3391         }
3392         mb_keep = VLC_FALSE;
3393     }
3394 }
3395
3396 EbmlElement* EbmlParser::UnGet( uint64 i_block_pos, uint64 i_cluster_pos )
3397 {
3398     if ( mi_user_level > mi_level )
3399     {
3400         while ( mi_user_level != mi_level )
3401         {
3402             delete m_el[mi_user_level];
3403             m_el[mi_user_level] = NULL;
3404             mi_user_level--;
3405         }
3406     }
3407     m_got = NULL;
3408     mb_keep = VLC_FALSE;
3409     if ( m_el[1]->GetElementPosition() == i_cluster_pos )
3410     {
3411         m_es->I_O().setFilePointer( i_block_pos, seek_beginning );
3412         return (EbmlMaster*) m_el[1];
3413     }
3414     else
3415     {
3416         // seek to the previous Cluster
3417         m_es->I_O().setFilePointer( i_cluster_pos, seek_beginning );
3418         mi_level--;
3419         mi_user_level--;
3420         delete m_el[mi_level];
3421         m_el[mi_level] = NULL;
3422         return NULL;
3423     }
3424 }
3425
3426 void EbmlParser::Up( void )
3427 {
3428     if( mi_user_level == mi_level )
3429     {
3430         fprintf( stderr," arrrrrrrrrrrrrg Up cannot escape itself\n" );
3431     }
3432
3433     mi_user_level--;
3434 }
3435
3436 void EbmlParser::Down( void )
3437 {
3438     mi_user_level++;
3439     mi_level++;
3440 }
3441
3442 void EbmlParser::Keep( void )
3443 {
3444     mb_keep = VLC_TRUE;
3445 }
3446
3447 int EbmlParser::GetLevel( void )
3448 {
3449     return mi_user_level;
3450 }
3451
3452 void EbmlParser::Reset( demux_t *p_demux )
3453 {
3454     while ( mi_level > 0)
3455     {
3456         delete m_el[mi_level];
3457         m_el[mi_level] = NULL;
3458         mi_level--;
3459     }
3460     mi_user_level = mi_level = 1;
3461 #if LIBEBML_VERSION >= 0x000704
3462     // a little faster and cleaner
3463     m_es->I_O().setFilePointer( static_cast<KaxSegment*>(m_el[0])->GetGlobalPosition(0) );
3464 #else
3465     m_es->I_O().setFilePointer( m_el[0]->GetElementPosition() + m_el[0]->ElementSize(true) - m_el[0]->GetSize() );
3466 #endif
3467     mb_dummy = config_GetInt( p_demux, "mkv-use-dummy" );
3468 }
3469
3470 EbmlElement *EbmlParser::Get( void )
3471 {
3472     int i_ulev = 0;
3473
3474     if( mi_user_level != mi_level )
3475     {
3476         return NULL;
3477     }
3478     if( m_got )
3479     {
3480         EbmlElement *ret = m_got;
3481         m_got = NULL;
3482
3483         return ret;
3484     }
3485
3486     if( m_el[mi_level] )
3487     {
3488         m_el[mi_level]->SkipData( *m_es, m_el[mi_level]->Generic().Context );
3489         if( !mb_keep )
3490         {
3491             delete m_el[mi_level];
3492         }
3493         mb_keep = VLC_FALSE;
3494     }
3495
3496     m_el[mi_level] = m_es->FindNextElement( m_el[mi_level - 1]->Generic().Context, i_ulev, 0xFFFFFFFFL, mb_dummy != 0, 1 );
3497 //    mi_remain_size[mi_level] = m_el[mi_level]->GetSize();
3498     if( i_ulev > 0 )
3499     {
3500         while( i_ulev > 0 )
3501         {
3502             if( mi_level == 1 )
3503             {
3504                 mi_level = 0;
3505                 return NULL;
3506             }
3507
3508             delete m_el[mi_level - 1];
3509             m_got = m_el[mi_level -1] = m_el[mi_level];
3510             m_el[mi_level] = NULL;
3511
3512             mi_level--;
3513             i_ulev--;
3514         }
3515         return NULL;
3516     }
3517     else if( m_el[mi_level] == NULL )
3518     {
3519         fprintf( stderr," m_el[mi_level] == NULL\n" );
3520     }
3521
3522     return m_el[mi_level];
3523 }
3524
3525
3526 /*****************************************************************************
3527  * Tools
3528  *  * LoadCues : load the cues element and update index
3529  *
3530  *  * LoadTags : load ... the tags element
3531  *
3532  *  * InformationCreate : create all information, load tags if present
3533  *
3534  *****************************************************************************/
3535 void matroska_segment_c::LoadCues( )
3536 {
3537     int64_t     i_sav_position = es.I_O().getFilePointer();
3538     EbmlParser  *ep;
3539     EbmlElement *el, *cues;
3540
3541     /* *** Load the cue if found *** */
3542     if( i_cues_position < 0 )
3543     {
3544         msg_Warn( &sys.demuxer, "no cues/empty cues found->seek won't be precise" );
3545
3546 //        IndexAppendCluster( cluster );
3547     }
3548
3549     vlc_bool_t b_seekable;
3550
3551     stream_Control( sys.demuxer.s, STREAM_CAN_FASTSEEK, &b_seekable );
3552     if( !b_seekable )
3553         return;
3554
3555     msg_Dbg( &sys.demuxer, "loading cues" );
3556     es.I_O().setFilePointer( i_cues_position, seek_beginning );
3557     cues = es.FindNextID( KaxCues::ClassInfos, 0xFFFFFFFFL);
3558
3559     if( cues == NULL )
3560     {
3561         msg_Err( &sys.demuxer, "cannot load cues (broken seekhead or file)" );
3562         es.I_O().setFilePointer( i_sav_position, seek_beginning );
3563         return;
3564     }
3565
3566     ep = new EbmlParser( &es, cues, &sys.demuxer );
3567     while( ( el = ep->Get() ) != NULL )
3568     {
3569         if( MKV_IS_ID( el, KaxCuePoint ) )
3570         {
3571 #define idx p_indexes[i_index]
3572
3573             idx.i_track       = -1;
3574             idx.i_block_number= -1;
3575             idx.i_position    = -1;
3576             idx.i_time        = 0;
3577             idx.b_key         = VLC_TRUE;
3578
3579             ep->Down();
3580             while( ( el = ep->Get() ) != NULL )
3581             {
3582                 if( MKV_IS_ID( el, KaxCueTime ) )
3583                 {
3584                     KaxCueTime &ctime = *(KaxCueTime*)el;
3585
3586                     ctime.ReadData( es.I_O() );
3587
3588                     idx.i_time = uint64( ctime ) * i_timescale / (mtime_t)1000;
3589                 }
3590                 else if( MKV_IS_ID( el, KaxCueTrackPositions ) )
3591                 {
3592                     ep->Down();
3593                     while( ( el = ep->Get() ) != NULL )
3594                     {
3595                         if( MKV_IS_ID( el, KaxCueTrack ) )
3596                         {
3597                             KaxCueTrack &ctrack = *(KaxCueTrack*)el;
3598
3599                             ctrack.ReadData( es.I_O() );
3600                             idx.i_track = uint16( ctrack );
3601                         }
3602                         else if( MKV_IS_ID( el, KaxCueClusterPosition ) )
3603                         {
3604                             KaxCueClusterPosition &ccpos = *(KaxCueClusterPosition*)el;
3605
3606                             ccpos.ReadData( es.I_O() );
3607                             idx.i_position = segment->GetGlobalPosition( uint64( ccpos ) );
3608                         }
3609                         else if( MKV_IS_ID( el, KaxCueBlockNumber ) )
3610                         {
3611                             KaxCueBlockNumber &cbnum = *(KaxCueBlockNumber*)el;
3612
3613                             cbnum.ReadData( es.I_O() );
3614                             idx.i_block_number = uint32( cbnum );
3615                         }
3616                         else
3617                         {
3618                             msg_Dbg( &sys.demuxer, "         * Unknown (%s)", typeid(*el).name() );
3619                         }
3620                     }
3621                     ep->Up();
3622                 }
3623                 else
3624                 {
3625                     msg_Dbg( &sys.demuxer, "     * Unknown (%s)", typeid(*el).name() );
3626                 }
3627             }
3628             ep->Up();
3629
3630 #if 0
3631             msg_Dbg( &sys.demuxer, " * added time="I64Fd" pos="I64Fd
3632                      " track=%d bnum=%d", idx.i_time, idx.i_position,
3633                      idx.i_track, idx.i_block_number );
3634 #endif
3635
3636             i_index++;
3637             if( i_index >= i_index_max )
3638             {
3639                 i_index_max += 1024;
3640                 p_indexes = (mkv_index_t*)realloc( p_indexes, sizeof( mkv_index_t ) * i_index_max );
3641             }
3642 #undef idx
3643         }
3644         else
3645         {
3646             msg_Dbg( &sys.demuxer, " * Unknown (%s)", typeid(*el).name() );
3647         }
3648     }
3649     delete ep;
3650     delete cues;
3651
3652     b_cues = VLC_TRUE;
3653
3654     msg_Dbg( &sys.demuxer, "loading cues done." );
3655     es.I_O().setFilePointer( i_sav_position, seek_beginning );
3656 }
3657
3658 void matroska_segment_c::LoadTags( )
3659 {
3660     int64_t     i_sav_position = es.I_O().getFilePointer();
3661     EbmlParser  *ep;
3662     EbmlElement *el, *tags;
3663
3664     msg_Dbg( &sys.demuxer, "loading tags" );
3665     es.I_O().setFilePointer( i_tags_position, seek_beginning );
3666     tags = es.FindNextID( KaxTags::ClassInfos, 0xFFFFFFFFL);
3667
3668     if( tags == NULL )
3669     {
3670         msg_Err( &sys.demuxer, "cannot load tags (broken seekhead or file)" );
3671         es.I_O().setFilePointer( i_sav_position, seek_beginning );
3672         return;
3673     }
3674
3675     msg_Dbg( &sys.demuxer, "Tags" );
3676     ep = new EbmlParser( &es, tags, &sys.demuxer );
3677     while( ( el = ep->Get() ) != NULL )
3678     {
3679         if( MKV_IS_ID( el, KaxTag ) )
3680         {
3681             msg_Dbg( &sys.demuxer, "+ Tag" );
3682             ep->Down();
3683             while( ( el = ep->Get() ) != NULL )
3684             {
3685                 if( MKV_IS_ID( el, KaxTagTargets ) )
3686                 {
3687                     msg_Dbg( &sys.demuxer, "|   + Targets" );
3688                     ep->Down();
3689                     while( ( el = ep->Get() ) != NULL )
3690                     {
3691                         msg_Dbg( &sys.demuxer, "|   |   + Unknown (%s)", typeid( *el ).name() );
3692                     }
3693                     ep->Up();
3694                 }
3695                 else if( MKV_IS_ID( el, KaxTagGeneral ) )
3696                 {
3697                     msg_Dbg( &sys.demuxer, "|   + General" );
3698                     ep->Down();
3699                     while( ( el = ep->Get() ) != NULL )
3700                     {
3701                         msg_Dbg( &sys.demuxer, "|   |   + Unknown (%s)", typeid( *el ).name() );
3702                     }
3703                     ep->Up();
3704                 }
3705                 else if( MKV_IS_ID( el, KaxTagGenres ) )
3706                 {
3707                     msg_Dbg( &sys.demuxer, "|   + Genres" );
3708                     ep->Down();
3709                     while( ( el = ep->Get() ) != NULL )
3710                     {
3711                         msg_Dbg( &sys.demuxer, "|   |   + Unknown (%s)", typeid( *el ).name() );
3712                     }
3713                     ep->Up();
3714                 }
3715                 else if( MKV_IS_ID( el, KaxTagAudioSpecific ) )
3716                 {
3717                     msg_Dbg( &sys.demuxer, "|   + Audio Specific" );
3718                     ep->Down();
3719                     while( ( el = ep->Get() ) != NULL )
3720                     {
3721                         msg_Dbg( &sys.demuxer, "|   |   + Unknown (%s)", typeid( *el ).name() );
3722                     }
3723                     ep->Up();
3724                 }
3725                 else if( MKV_IS_ID( el, KaxTagImageSpecific ) )
3726                 {
3727                     msg_Dbg( &sys.demuxer, "|   + Images Specific" );
3728                     ep->Down();
3729                     while( ( el = ep->Get() ) != NULL )
3730                     {
3731                         msg_Dbg( &sys.demuxer, "|   |   + Unknown (%s)", typeid( *el ).name() );
3732                     }
3733                     ep->Up();
3734                 }
3735                 else if( MKV_IS_ID( el, KaxTagMultiComment ) )
3736                 {
3737                     msg_Dbg( &sys.demuxer, "|   + Multi Comment" );
3738                 }
3739                 else if( MKV_IS_ID( el, KaxTagMultiCommercial ) )
3740                 {
3741                     msg_Dbg( &sys.demuxer, "|   + Multi Commercial" );
3742                 }
3743                 else if( MKV_IS_ID( el, KaxTagMultiDate ) )
3744                 {
3745                     msg_Dbg( &sys.demuxer, "|   + Multi Date" );
3746                 }
3747                 else if( MKV_IS_ID( el, KaxTagMultiEntity ) )
3748                 {
3749                     msg_Dbg( &sys.demuxer, "|   + Multi Entity" );
3750                 }
3751                 else if( MKV_IS_ID( el, KaxTagMultiIdentifier ) )
3752                 {
3753                     msg_Dbg( &sys.demuxer, "|   + Multi Identifier" );
3754                 }
3755                 else if( MKV_IS_ID( el, KaxTagMultiLegal ) )
3756                 {
3757                     msg_Dbg( &sys.demuxer, "|   + Multi Legal" );
3758                 }
3759                 else if( MKV_IS_ID( el, KaxTagMultiTitle ) )
3760                 {
3761                     msg_Dbg( &sys.demuxer, "|   + Multi Title" );
3762                 }
3763                 else
3764                 {
3765                     msg_Dbg( &sys.demuxer, "|   + Unknown (%s)", typeid( *el ).name() );
3766                 }
3767             }
3768             ep->Up();
3769         }
3770         else
3771         {
3772             msg_Dbg( &sys.demuxer, "+ Unknown (%s)", typeid( *el ).name() );
3773         }
3774     }
3775     delete ep;
3776     delete tags;
3777
3778     msg_Dbg( &sys.demuxer, "loading tags done." );
3779     es.I_O().setFilePointer( i_sav_position, seek_beginning );
3780 }
3781
3782 /*****************************************************************************
3783  * ParseSeekHead:
3784  *****************************************************************************/
3785 void matroska_segment_c::ParseSeekHead( KaxSeekHead *seekhead )
3786 {
3787     EbmlElement *el;
3788     size_t i, j;
3789     int i_upper_level = 0;
3790
3791     msg_Dbg( &sys.demuxer, "|   + Seek head" );
3792
3793     /* Master elements */
3794     seekhead->Read( es, seekhead->Generic().Context, i_upper_level, el, true );
3795
3796     for( i = 0; i < seekhead->ListSize(); i++ )
3797     {
3798         EbmlElement *l = (*seekhead)[i];
3799
3800         if( MKV_IS_ID( l, KaxSeek ) )
3801         {
3802             EbmlMaster *sk = static_cast<EbmlMaster *>(l);
3803             EbmlId id = EbmlVoid::ClassInfos.GlobalId;
3804             int64_t i_pos = -1;
3805
3806             for( j = 0; j < sk->ListSize(); j++ )
3807             {
3808                 EbmlElement *l = (*sk)[j];
3809
3810                 if( MKV_IS_ID( l, KaxSeekID ) )
3811                 {
3812                     KaxSeekID &sid = *(KaxSeekID*)l;
3813                     id = EbmlId( sid.GetBuffer(), sid.GetSize() );
3814                 }
3815                 else if( MKV_IS_ID( l, KaxSeekPosition ) )
3816                 {
3817                     KaxSeekPosition &spos = *(KaxSeekPosition*)l;
3818                     i_pos = uint64( spos );
3819                 }
3820                 else
3821                 {
3822                     msg_Dbg( &sys.demuxer, "|   |   |   + Unknown (%s)", typeid(*l).name() );
3823                 }
3824             }
3825
3826             if( i_pos >= 0 )
3827             {
3828                 if( id == KaxCues::ClassInfos.GlobalId )
3829                 {
3830                     msg_Dbg( &sys.demuxer, "|   |   |   = cues at "I64Fd, i_pos );
3831                     i_cues_position = segment->GetGlobalPosition( i_pos );
3832                 }
3833                 else if( id == KaxChapters::ClassInfos.GlobalId )
3834                 {
3835                     msg_Dbg( &sys.demuxer, "|   |   |   = chapters at "I64Fd, i_pos );
3836                     i_chapters_position = segment->GetGlobalPosition( i_pos );
3837                 }
3838                 else if( id == KaxTags::ClassInfos.GlobalId )
3839                 {
3840                     msg_Dbg( &sys.demuxer, "|   |   |   = tags at "I64Fd, i_pos );
3841                     i_tags_position = segment->GetGlobalPosition( i_pos );
3842                 }
3843             }
3844         }
3845         else
3846         {
3847             msg_Dbg( &sys.demuxer, "|   |   + Unknown (%s)", typeid(*l).name() );
3848         }
3849     }
3850 }
3851
3852 /*****************************************************************************
3853  * ParseTrackEntry:
3854  *****************************************************************************/
3855 void matroska_segment_c::ParseTrackEntry( KaxTrackEntry *m )
3856 {
3857     size_t i, j, k, n;
3858
3859     mkv_track_t *tk;
3860
3861     msg_Dbg( &sys.demuxer, "|   |   + Track Entry" );
3862
3863     tk = new mkv_track_t();
3864     tracks.push_back( tk );
3865
3866     /* Init the track */
3867     memset( tk, 0, sizeof( mkv_track_t ) );
3868
3869     es_format_Init( &tk->fmt, UNKNOWN_ES, 0 );
3870     tk->fmt.psz_language = strdup("English");
3871     tk->fmt.psz_description = NULL;
3872
3873     tk->b_default = VLC_TRUE;
3874     tk->b_enabled = VLC_TRUE;
3875     tk->b_silent = VLC_FALSE;
3876     tk->i_number = tracks.size() - 1;
3877     tk->i_extra_data = 0;
3878     tk->p_extra_data = NULL;
3879     tk->psz_codec = NULL;
3880     tk->i_default_duration = 0;
3881     tk->f_timecodescale = 1.0;
3882
3883     tk->b_inited = VLC_FALSE;
3884     tk->i_data_init = 0;
3885     tk->p_data_init = NULL;
3886
3887     tk->psz_codec_name = NULL;
3888     tk->psz_codec_settings = NULL;
3889     tk->psz_codec_info_url = NULL;
3890     tk->psz_codec_download_url = NULL;
3891     
3892     tk->i_compression_type = MATROSKA_COMPRESSION_NONE;
3893
3894     for( i = 0; i < m->ListSize(); i++ )
3895     {
3896         EbmlElement *l = (*m)[i];
3897
3898         if( MKV_IS_ID( l, KaxTrackNumber ) )
3899         {
3900             KaxTrackNumber &tnum = *(KaxTrackNumber*)l;
3901
3902             tk->i_number = uint32( tnum );
3903             msg_Dbg( &sys.demuxer, "|   |   |   + Track Number=%u", uint32( tnum ) );
3904         }
3905         else  if( MKV_IS_ID( l, KaxTrackUID ) )
3906         {
3907             KaxTrackUID &tuid = *(KaxTrackUID*)l;
3908
3909             msg_Dbg( &sys.demuxer, "|   |   |   + Track UID=%u",  uint32( tuid ) );
3910         }
3911         else  if( MKV_IS_ID( l, KaxTrackType ) )
3912         {
3913             char *psz_type;
3914             KaxTrackType &ttype = *(KaxTrackType*)l;
3915
3916             switch( uint8(ttype) )
3917             {
3918                 case track_audio:
3919                     psz_type = "audio";
3920                     tk->fmt.i_cat = AUDIO_ES;
3921                     break;
3922                 case track_video:
3923                     psz_type = "video";
3924                     tk->fmt.i_cat = VIDEO_ES;
3925                     break;
3926                 case track_subtitle:
3927                     psz_type = "subtitle";
3928                     tk->fmt.i_cat = SPU_ES;
3929                     break;
3930                 case track_buttons:
3931                     psz_type = "buttons";
3932                     tk->fmt.i_cat = SPU_ES;
3933                     break;
3934                 default:
3935                     psz_type = "unknown";
3936                     tk->fmt.i_cat = UNKNOWN_ES;
3937                     break;
3938             }
3939
3940             msg_Dbg( &sys.demuxer, "|   |   |   + Track Type=%s", psz_type );
3941         }
3942 //        else  if( EbmlId( *l ) == KaxTrackFlagEnabled::ClassInfos.GlobalId )
3943 //        {
3944 //            KaxTrackFlagEnabled &fenb = *(KaxTrackFlagEnabled*)l;
3945
3946 //            tk->b_enabled = uint32( fenb );
3947 //            msg_Dbg( &sys.demuxer, "|   |   |   + Track Enabled=%u",
3948 //                     uint32( fenb )  );
3949 //        }
3950         else  if( MKV_IS_ID( l, KaxTrackFlagDefault ) )
3951         {
3952             KaxTrackFlagDefault &fdef = *(KaxTrackFlagDefault*)l;
3953
3954             tk->b_default = uint32( fdef );
3955             msg_Dbg( &sys.demuxer, "|   |   |   + Track Default=%u", uint32( fdef )  );
3956         }
3957         else  if( MKV_IS_ID( l, KaxTrackFlagLacing ) )
3958         {
3959             KaxTrackFlagLacing &lac = *(KaxTrackFlagLacing*)l;
3960
3961             msg_Dbg( &sys.demuxer, "|   |   |   + Track Lacing=%d", uint32( lac ) );
3962         }
3963         else  if( MKV_IS_ID( l, KaxTrackMinCache ) )
3964         {
3965             KaxTrackMinCache &cmin = *(KaxTrackMinCache*)l;
3966
3967             msg_Dbg( &sys.demuxer, "|   |   |   + Track MinCache=%d", uint32( cmin ) );
3968         }
3969         else  if( MKV_IS_ID( l, KaxTrackMaxCache ) )
3970         {
3971             KaxTrackMaxCache &cmax = *(KaxTrackMaxCache*)l;
3972
3973             msg_Dbg( &sys.demuxer, "|   |   |   + Track MaxCache=%d", uint32( cmax ) );
3974         }
3975         else  if( MKV_IS_ID( l, KaxTrackDefaultDuration ) )
3976         {
3977             KaxTrackDefaultDuration &defd = *(KaxTrackDefaultDuration*)l;
3978
3979             tk->i_default_duration = uint64(defd);
3980             msg_Dbg( &sys.demuxer, "|   |   |   + Track Default Duration="I64Fd, uint64(defd) );
3981         }
3982         else  if( MKV_IS_ID( l, KaxTrackTimecodeScale ) )
3983         {
3984             KaxTrackTimecodeScale &ttcs = *(KaxTrackTimecodeScale*)l;
3985
3986             tk->f_timecodescale = float( ttcs );
3987             msg_Dbg( &sys.demuxer, "|   |   |   + Track TimeCodeScale=%f", tk->f_timecodescale );
3988         }
3989         else if( MKV_IS_ID( l, KaxTrackName ) )
3990         {
3991             KaxTrackName &tname = *(KaxTrackName*)l;
3992
3993             tk->fmt.psz_description = ToUTF8( UTFstring( tname ) );
3994             msg_Dbg( &sys.demuxer, "|   |   |   + Track Name=%s", tk->fmt.psz_description );
3995         }
3996         else  if( MKV_IS_ID( l, KaxTrackLanguage ) )
3997         {
3998             KaxTrackLanguage &lang = *(KaxTrackLanguage*)l;
3999
4000             if ( tk->fmt.psz_language != NULL )
4001                 free( tk->fmt.psz_language );
4002             tk->fmt.psz_language = strdup( string( lang ).c_str() );
4003             msg_Dbg( &sys.demuxer,
4004                      "|   |   |   + Track Language=`%s'", tk->fmt.psz_language );
4005         }
4006         else  if( MKV_IS_ID( l, KaxCodecID ) )
4007         {
4008             KaxCodecID &codecid = *(KaxCodecID*)l;
4009
4010             tk->psz_codec = strdup( string( codecid ).c_str() );
4011             msg_Dbg( &sys.demuxer, "|   |   |   + Track CodecId=%s", string( codecid ).c_str() );
4012         }
4013         else  if( MKV_IS_ID( l, KaxCodecPrivate ) )
4014         {
4015             KaxCodecPrivate &cpriv = *(KaxCodecPrivate*)l;
4016
4017             tk->i_extra_data = cpriv.GetSize();
4018             if( tk->i_extra_data > 0 )
4019             {
4020                 tk->p_extra_data = (uint8_t*)malloc( tk->i_extra_data );
4021                 memcpy( tk->p_extra_data, cpriv.GetBuffer(), tk->i_extra_data );
4022             }
4023             msg_Dbg( &sys.demuxer, "|   |   |   + Track CodecPrivate size="I64Fd, cpriv.GetSize() );
4024         }
4025         else if( MKV_IS_ID( l, KaxCodecName ) )
4026         {
4027             KaxCodecName &cname = *(KaxCodecName*)l;
4028
4029             tk->psz_codec_name = ToUTF8( UTFstring( cname ) );
4030             msg_Dbg( &sys.demuxer, "|   |   |   + Track Codec Name=%s", tk->psz_codec_name );
4031         }
4032         else if( MKV_IS_ID( l, KaxContentEncodings ) )
4033         {
4034             EbmlMaster *cencs = static_cast<EbmlMaster*>(l);
4035             MkvTree( sys.demuxer, 3, "Content Encodings" );
4036             for( j = 0; j < cencs->ListSize(); j++ )
4037             {
4038                 EbmlElement *l2 = (*cencs)[j];
4039                 if( MKV_IS_ID( l2, KaxContentEncoding ) )
4040                 {
4041                     MkvTree( sys.demuxer, 4, "Content Encoding" );
4042                     EbmlMaster *cenc = static_cast<EbmlMaster*>(l2);
4043                     for( k = 0; k < cenc->ListSize(); k++ )
4044                     {
4045                         EbmlElement *l3 = (*cenc)[k];
4046                         if( MKV_IS_ID( l3, KaxContentEncodingOrder ) )
4047                         {
4048                             KaxContentEncodingOrder &encord = *(KaxContentEncodingOrder*)l3;
4049                             MkvTree( sys.demuxer, 5, "Order: %i", uint32( encord ) );
4050                         }
4051                         else if( MKV_IS_ID( l3, KaxContentEncodingScope ) )
4052                         {
4053                             KaxContentEncodingScope &encscope = *(KaxContentEncodingScope*)l3;
4054                             MkvTree( sys.demuxer, 5, "Scope: %i", uint32( encscope ) );
4055                         }
4056                         else if( MKV_IS_ID( l3, KaxContentEncodingType ) )
4057                         {
4058                             KaxContentEncodingType &enctype = *(KaxContentEncodingType*)l3;
4059                             MkvTree( sys.demuxer, 5, "Type: %i", uint32( enctype ) );
4060                         }
4061                         else if( MKV_IS_ID( l3, KaxContentCompression ) )
4062                         {
4063                             EbmlMaster *compr = static_cast<EbmlMaster*>(l3);
4064                             MkvTree( sys.demuxer, 5, "Content Compression" );
4065                             for( n = 0; n < compr->ListSize(); n++ )
4066                             {
4067                                 EbmlElement *l4 = (*compr)[n];
4068                                 if( MKV_IS_ID( l4, KaxContentCompAlgo ) )
4069                                 {
4070                                     KaxContentCompAlgo &compalg = *(KaxContentCompAlgo*)l4;
4071                                     MkvTree( sys.demuxer, 6, "Compression Algorithm: %i", uint32(compalg) );
4072                                     if( uint32( compalg ) == 0 )
4073                                     {
4074                                         tk->i_compression_type = MATROSKA_COMPRESSION_ZLIB;
4075                                     }
4076                                 }
4077                                 else
4078                                 {
4079                                     MkvTree( sys.demuxer, 6, "Unknown (%s)", typeid(*l4).name() );
4080                                 }
4081                             }
4082                         }
4083
4084                         else
4085                         {
4086                             MkvTree( sys.demuxer, 5, "Unknown (%s)", typeid(*l3).name() );
4087                         }
4088                     }
4089                     
4090                 }
4091                 else
4092                 {
4093                     MkvTree( sys.demuxer, 4, "Unknown (%s)", typeid(*l2).name() );
4094                 }
4095             }
4096                 
4097         }
4098 //        else if( EbmlId( *l ) == KaxCodecSettings::ClassInfos.GlobalId )
4099 //        {
4100 //            KaxCodecSettings &cset = *(KaxCodecSettings*)l;
4101
4102 //            tk->psz_codec_settings = ToUTF8( UTFstring( cset ) );
4103 //            msg_Dbg( &sys.demuxer, "|   |   |   + Track Codec Settings=%s", tk->psz_codec_settings );
4104 //        }
4105 //        else if( EbmlId( *l ) == KaxCodecInfoURL::ClassInfos.GlobalId )
4106 //        {
4107 //            KaxCodecInfoURL &ciurl = *(KaxCodecInfoURL*)l;
4108
4109 //            tk->psz_codec_info_url = strdup( string( ciurl ).c_str() );
4110 //            msg_Dbg( &sys.demuxer, "|   |   |   + Track Codec Info URL=%s", tk->psz_codec_info_url );
4111 //        }
4112 //        else if( EbmlId( *l ) == KaxCodecDownloadURL::ClassInfos.GlobalId )
4113 //        {
4114 //            KaxCodecDownloadURL &cdurl = *(KaxCodecDownloadURL*)l;
4115
4116 //            tk->psz_codec_download_url = strdup( string( cdurl ).c_str() );
4117 //            msg_Dbg( &sys.demuxer, "|   |   |   + Track Codec Info URL=%s", tk->psz_codec_download_url );
4118 //        }
4119 //        else if( EbmlId( *l ) == KaxCodecDecodeAll::ClassInfos.GlobalId )
4120 //        {
4121 //            KaxCodecDecodeAll &cdall = *(KaxCodecDecodeAll*)l;
4122
4123 //            msg_Dbg( &sys.demuxer, "|   |   |   + Track Codec Decode All=%u <== UNUSED", uint8( cdall ) );
4124 //        }
4125 //        else if( EbmlId( *l ) == KaxTrackOverlay::ClassInfos.GlobalId )
4126 //        {
4127 //            KaxTrackOverlay &tovr = *(KaxTrackOverlay*)l;
4128
4129 //            msg_Dbg( &sys.demuxer, "|   |   |   + Track Overlay=%u <== UNUSED", uint32( tovr ) );
4130 //        }
4131         else  if( MKV_IS_ID( l, KaxTrackVideo ) )
4132         {
4133             EbmlMaster *tkv = static_cast<EbmlMaster*>(l);
4134             unsigned int j;
4135
4136             msg_Dbg( &sys.demuxer, "|   |   |   + Track Video" );
4137             tk->f_fps = 0.0;
4138
4139             tk->fmt.video.i_frame_rate_base = (unsigned int)(tk->i_default_duration / 1000);
4140             tk->fmt.video.i_frame_rate = 1000000;     
4141             
4142             for( j = 0; j < tkv->ListSize(); j++ )
4143             {
4144                 EbmlElement *l = (*tkv)[j];
4145 //                if( EbmlId( *el4 ) == KaxVideoFlagInterlaced::ClassInfos.GlobalId )
4146 //                {
4147 //                    KaxVideoFlagInterlaced &fint = *(KaxVideoFlagInterlaced*)el4;
4148
4149 //                    msg_Dbg( &sys.demuxer, "|   |   |   |   + Track Video Interlaced=%u", uint8( fint ) );
4150 //                }
4151 //                else if( EbmlId( *el4 ) == KaxVideoStereoMode::ClassInfos.GlobalId )
4152 //                {
4153 //                    KaxVideoStereoMode &stereo = *(KaxVideoStereoMode*)el4;
4154
4155 //                    msg_Dbg( &sys.demuxer, "|   |   |   |   + Track Video Stereo Mode=%u", uint8( stereo ) );
4156 //                }
4157 //                else
4158                 if( MKV_IS_ID( l, KaxVideoPixelWidth ) )
4159                 {
4160                     KaxVideoPixelWidth &vwidth = *(KaxVideoPixelWidth*)l;
4161
4162                     tk->fmt.video.i_width = uint16( vwidth );
4163                     msg_Dbg( &sys.demuxer, "|   |   |   |   + width=%d", uint16( vwidth ) );
4164                 }
4165                 else if( MKV_IS_ID( l, KaxVideoPixelHeight ) )
4166                 {
4167                     KaxVideoPixelWidth &vheight = *(KaxVideoPixelWidth*)l;
4168
4169                     tk->fmt.video.i_height = uint16( vheight );
4170                     msg_Dbg( &sys.demuxer, "|   |   |   |   + height=%d", uint16( vheight ) );
4171                 }
4172                 else if( MKV_IS_ID( l, KaxVideoDisplayWidth ) )
4173                 {
4174                     KaxVideoDisplayWidth &vwidth = *(KaxVideoDisplayWidth*)l;
4175
4176                     tk->fmt.video.i_visible_width = uint16( vwidth );
4177                     msg_Dbg( &sys.demuxer, "|   |   |   |   + display width=%d", uint16( vwidth ) );
4178                 }
4179                 else if( MKV_IS_ID( l, KaxVideoDisplayHeight ) )
4180                 {
4181                     KaxVideoDisplayWidth &vheight = *(KaxVideoDisplayWidth*)l;
4182
4183                     tk->fmt.video.i_visible_height = uint16( vheight );
4184                     msg_Dbg( &sys.demuxer, "|   |   |   |   + display height=%d", uint16( vheight ) );
4185                 }
4186                 else if( MKV_IS_ID( l, KaxVideoFrameRate ) )
4187                 {
4188                     KaxVideoFrameRate &vfps = *(KaxVideoFrameRate*)l;
4189
4190                     tk->f_fps = float( vfps );
4191                     msg_Dbg( &sys.demuxer, "   |   |   |   + fps=%f", float( vfps ) );
4192                 }
4193 //                else if( EbmlId( *l ) == KaxVideoDisplayUnit::ClassInfos.GlobalId )
4194 //                {
4195 //                     KaxVideoDisplayUnit &vdmode = *(KaxVideoDisplayUnit*)l;
4196
4197 //                    msg_Dbg( &sys.demuxer, "|   |   |   |   + Track Video Display Unit=%s",
4198 //                             uint8( vdmode ) == 0 ? "pixels" : ( uint8( vdmode ) == 1 ? "centimeters": "inches" ) );
4199 //                }
4200 //                else if( EbmlId( *l ) == KaxVideoAspectRatio::ClassInfos.GlobalId )
4201 //                {
4202 //                    KaxVideoAspectRatio &ratio = *(KaxVideoAspectRatio*)l;
4203
4204 //                    msg_Dbg( &sys.demuxer, "   |   |   |   + Track Video Aspect Ratio Type=%u", uint8( ratio ) );
4205 //                }
4206 //                else if( EbmlId( *l ) == KaxVideoGamma::ClassInfos.GlobalId )
4207 //                {
4208 //                    KaxVideoGamma &gamma = *(KaxVideoGamma*)l;
4209
4210 //                    msg_Dbg( &sys.demuxer, "   |   |   |   + fps=%f", float( gamma ) );
4211 //                }
4212                 else
4213                 {
4214                     msg_Dbg( &sys.demuxer, "|   |   |   |   + Unknown (%s)", typeid(*l).name() );
4215                 }
4216             }
4217             if ( tk->fmt.video.i_visible_height && tk->fmt.video.i_visible_width )
4218                 tk->fmt.video.i_aspect = VOUT_ASPECT_FACTOR * tk->fmt.video.i_visible_width / tk->fmt.video.i_visible_height;
4219         }
4220         else  if( MKV_IS_ID( l, KaxTrackAudio ) )
4221         {
4222             EbmlMaster *tka = static_cast<EbmlMaster*>(l);
4223             unsigned int j;
4224
4225             msg_Dbg( &sys.demuxer, "|   |   |   + Track Audio" );
4226
4227             for( j = 0; j < tka->ListSize(); j++ )
4228             {
4229                 EbmlElement *l = (*tka)[j];
4230
4231                 if( MKV_IS_ID( l, KaxAudioSamplingFreq ) )
4232                 {
4233                     KaxAudioSamplingFreq &afreq = *(KaxAudioSamplingFreq*)l;
4234
4235                     tk->fmt.audio.i_rate = (int)float( afreq );
4236                     msg_Dbg( &sys.demuxer, "|   |   |   |   + afreq=%d", tk->fmt.audio.i_rate );
4237                 }
4238                 else if( MKV_IS_ID( l, KaxAudioChannels ) )
4239                 {
4240                     KaxAudioChannels &achan = *(KaxAudioChannels*)l;
4241
4242                     tk->fmt.audio.i_channels = uint8( achan );
4243                     msg_Dbg( &sys.demuxer, "|   |   |   |   + achan=%u", uint8( achan ) );
4244                 }
4245                 else if( MKV_IS_ID( l, KaxAudioBitDepth ) )
4246                 {
4247                     KaxAudioBitDepth &abits = *(KaxAudioBitDepth*)l;
4248
4249                     tk->fmt.audio.i_bitspersample = uint8( abits );
4250                     msg_Dbg( &sys.demuxer, "|   |   |   |   + abits=%u", uint8( abits ) );
4251                 }
4252                 else
4253                 {
4254                     msg_Dbg( &sys.demuxer, "|   |   |   |   + Unknown (%s)", typeid(*l).name() );
4255                 }
4256             }
4257         }
4258         else
4259         {
4260             msg_Dbg( &sys.demuxer, "|   |   |   + Unknown (%s)",
4261                      typeid(*l).name() );
4262         }
4263     }
4264 }
4265
4266 /*****************************************************************************
4267  * ParseTracks:
4268  *****************************************************************************/
4269 void matroska_segment_c::ParseTracks( KaxTracks *tracks )
4270 {
4271     EbmlElement *el;
4272     unsigned int i;
4273     int i_upper_level = 0;
4274
4275     msg_Dbg( &sys.demuxer, "|   + Tracks" );
4276
4277     /* Master elements */
4278     tracks->Read( es, tracks->Generic().Context, i_upper_level, el, true );
4279
4280     for( i = 0; i < tracks->ListSize(); i++ )
4281     {
4282         EbmlElement *l = (*tracks)[i];
4283
4284         if( MKV_IS_ID( l, KaxTrackEntry ) )
4285         {
4286             ParseTrackEntry( static_cast<KaxTrackEntry *>(l) );
4287         }
4288         else
4289         {
4290             msg_Dbg( &sys.demuxer, "|   |   + Unknown (%s)", typeid(*l).name() );
4291         }
4292     }
4293 }
4294
4295 /*****************************************************************************
4296  * ParseInfo:
4297  *****************************************************************************/
4298 void matroska_segment_c::ParseInfo( KaxInfo *info )
4299 {
4300     EbmlElement *el;
4301     EbmlMaster  *m;
4302     size_t i, j;
4303     int i_upper_level = 0;
4304
4305     msg_Dbg( &sys.demuxer, "|   + Information" );
4306
4307     /* Master elements */
4308     m = static_cast<EbmlMaster *>(info);
4309     m->Read( es, info->Generic().Context, i_upper_level, el, true );
4310
4311     for( i = 0; i < m->ListSize(); i++ )
4312     {
4313         EbmlElement *l = (*m)[i];
4314
4315         if( MKV_IS_ID( l, KaxSegmentUID ) )
4316         {
4317             if ( p_segment_uid == NULL )
4318                 p_segment_uid = new KaxSegmentUID(*static_cast<KaxSegmentUID*>(l));
4319
4320             msg_Dbg( &sys.demuxer, "|   |   + UID=%d", *(uint32*)p_segment_uid->GetBuffer() );
4321         }
4322         else if( MKV_IS_ID( l, KaxPrevUID ) )
4323         {
4324             if ( p_prev_segment_uid == NULL )
4325                 p_prev_segment_uid = new KaxPrevUID(*static_cast<KaxPrevUID*>(l));
4326
4327             msg_Dbg( &sys.demuxer, "|   |   + PrevUID=%d", *(uint32*)p_prev_segment_uid->GetBuffer() );
4328         }
4329         else if( MKV_IS_ID( l, KaxNextUID ) )
4330         {
4331             if ( p_next_segment_uid == NULL )
4332                 p_next_segment_uid = new KaxNextUID(*static_cast<KaxNextUID*>(l));
4333
4334             msg_Dbg( &sys.demuxer, "|   |   + NextUID=%d", *(uint32*)p_next_segment_uid->GetBuffer() );
4335         }
4336         else if( MKV_IS_ID( l, KaxTimecodeScale ) )
4337         {
4338             KaxTimecodeScale &tcs = *(KaxTimecodeScale*)l;
4339
4340             i_timescale = uint64(tcs);
4341
4342             msg_Dbg( &sys.demuxer, "|   |   + TimecodeScale="I64Fd,
4343                      i_timescale );
4344         }
4345         else if( MKV_IS_ID( l, KaxDuration ) )
4346         {
4347             KaxDuration &dur = *(KaxDuration*)l;
4348
4349             i_duration = mtime_t( double( dur ) );
4350
4351             msg_Dbg( &sys.demuxer, "|   |   + Duration="I64Fd,
4352                      i_duration );
4353         }
4354         else if( MKV_IS_ID( l, KaxMuxingApp ) )
4355         {
4356             KaxMuxingApp &mapp = *(KaxMuxingApp*)l;
4357
4358             psz_muxing_application = ToUTF8( UTFstring( mapp ) );
4359
4360             msg_Dbg( &sys.demuxer, "|   |   + Muxing Application=%s",
4361                      psz_muxing_application );
4362         }
4363         else if( MKV_IS_ID( l, KaxWritingApp ) )
4364         {
4365             KaxWritingApp &wapp = *(KaxWritingApp*)l;
4366
4367             psz_writing_application = ToUTF8( UTFstring( wapp ) );
4368
4369             msg_Dbg( &sys.demuxer, "|   |   + Writing Application=%s",
4370                      psz_writing_application );
4371         }
4372         else if( MKV_IS_ID( l, KaxSegmentFilename ) )
4373         {
4374             KaxSegmentFilename &sfn = *(KaxSegmentFilename*)l;
4375
4376             psz_segment_filename = ToUTF8( UTFstring( sfn ) );
4377
4378             msg_Dbg( &sys.demuxer, "|   |   + Segment Filename=%s",
4379                      psz_segment_filename );
4380         }
4381         else if( MKV_IS_ID( l, KaxTitle ) )
4382         {
4383             KaxTitle &title = *(KaxTitle*)l;
4384
4385             psz_title = ToUTF8( UTFstring( title ) );
4386
4387             msg_Dbg( &sys.demuxer, "|   |   + Title=%s", psz_title );
4388         }
4389         else if( MKV_IS_ID( l, KaxSegmentFamily ) )
4390         {
4391             KaxSegmentFamily *uid = static_cast<KaxSegmentFamily*>(l);
4392
4393             families.push_back( new KaxSegmentFamily(*uid) );
4394
4395             msg_Dbg( &sys.demuxer, "|   |   + family=%d", *(uint32*)uid->GetBuffer() );
4396         }
4397 #if defined( HAVE_GMTIME_R ) && !defined( SYS_DARWIN )
4398         else if( MKV_IS_ID( l, KaxDateUTC ) )
4399         {
4400             KaxDateUTC &date = *(KaxDateUTC*)l;
4401             time_t i_date;
4402             struct tm tmres;
4403             char   buffer[256];
4404
4405             i_date = date.GetEpochDate();
4406             memset( buffer, 0, 256 );
4407             if( gmtime_r( &i_date, &tmres ) &&
4408                 asctime_r( &tmres, buffer ) )
4409             {
4410                 buffer[strlen( buffer)-1]= '\0';
4411                 psz_date_utc = strdup( buffer );
4412                 msg_Dbg( &sys.demuxer, "|   |   + Date=%s", psz_date_utc );
4413             }
4414         }
4415 #endif
4416 #if LIBMATROSKA_VERSION >= 0x000704
4417         else if( MKV_IS_ID( l, KaxChapterTranslate ) )
4418         {
4419             KaxChapterTranslate *p_trans = static_cast<KaxChapterTranslate*>( l );
4420             chapter_translation_c *p_translate = new chapter_translation_c();
4421
4422             p_trans->Read( es, p_trans->Generic().Context, i_upper_level, el, true );
4423             for( j = 0; j < p_trans->ListSize(); j++ )
4424             {
4425                 EbmlElement *l = (*p_trans)[j];
4426
4427                 if( MKV_IS_ID( l, KaxChapterTranslateEditionUID ) )
4428                 {
4429                     p_translate->editions.push_back( uint64( *static_cast<KaxChapterTranslateEditionUID*>( l ) ) );
4430                 }
4431                 else if( MKV_IS_ID( l, KaxChapterTranslateCodec ) )
4432                 {
4433                     p_translate->codec_id = uint32( *static_cast<KaxChapterTranslateCodec*>( l ) );
4434                 }
4435                 else if( MKV_IS_ID( l, KaxChapterTranslateID ) )
4436                 {
4437                     p_translate->p_translated = new KaxChapterTranslateID( *static_cast<KaxChapterTranslateID*>( l ) );
4438                 }
4439             }
4440
4441             translations.push_back( p_translate );
4442         }
4443 #endif
4444         else
4445         {
4446             msg_Dbg( &sys.demuxer, "|   |   + Unknown (%s)", typeid(*l).name() );
4447         }
4448     }
4449
4450     double f_dur = double(i_duration) * double(i_timescale) / 1000000.0;
4451     i_duration = mtime_t(f_dur);
4452 }
4453
4454
4455 /*****************************************************************************
4456  * ParseChapterAtom
4457  *****************************************************************************/
4458 void matroska_segment_c::ParseChapterAtom( int i_level, KaxChapterAtom *ca, chapter_item_c & chapters )
4459 {
4460     size_t i, j;
4461
4462     msg_Dbg( &sys.demuxer, "|   |   |   + ChapterAtom (level=%d)", i_level );
4463     for( i = 0; i < ca->ListSize(); i++ )
4464     {
4465         EbmlElement *l = (*ca)[i];
4466
4467         if( MKV_IS_ID( l, KaxChapterUID ) )
4468         {
4469             chapters.i_uid = uint64_t(*(KaxChapterUID*)l);
4470             msg_Dbg( &sys.demuxer, "|   |   |   |   + ChapterUID: %lld", chapters.i_uid );
4471         }
4472         else if( MKV_IS_ID( l, KaxChapterFlagHidden ) )
4473         {
4474             KaxChapterFlagHidden &flag =*(KaxChapterFlagHidden*)l;
4475             chapters.b_display_seekpoint = uint8( flag ) == 0;
4476
4477             msg_Dbg( &sys.demuxer, "|   |   |   |   + ChapterFlagHidden: %s", chapters.b_display_seekpoint ? "no":"yes" );
4478         }
4479         else if( MKV_IS_ID( l, KaxChapterTimeStart ) )
4480         {
4481             KaxChapterTimeStart &start =*(KaxChapterTimeStart*)l;
4482             chapters.i_start_time = uint64( start ) / I64C(1000);
4483
4484             msg_Dbg( &sys.demuxer, "|   |   |   |   + ChapterTimeStart: %lld", chapters.i_start_time );
4485         }
4486         else if( MKV_IS_ID( l, KaxChapterTimeEnd ) )
4487         {
4488             KaxChapterTimeEnd &end =*(KaxChapterTimeEnd*)l;
4489             chapters.i_end_time = uint64( end ) / I64C(1000);
4490
4491             msg_Dbg( &sys.demuxer, "|   |   |   |   + ChapterTimeEnd: %lld", chapters.i_end_time );
4492         }
4493         else if( MKV_IS_ID( l, KaxChapterDisplay ) )
4494         {
4495             EbmlMaster *cd = static_cast<EbmlMaster *>(l);
4496
4497             msg_Dbg( &sys.demuxer, "|   |   |   |   + ChapterDisplay" );
4498             for( j = 0; j < cd->ListSize(); j++ )
4499             {
4500                 EbmlElement *l= (*cd)[j];
4501
4502                 if( MKV_IS_ID( l, KaxChapterString ) )
4503                 {
4504                     int k;
4505
4506                     KaxChapterString &name =*(KaxChapterString*)l;
4507                     for (k = 0; k < i_level; k++)
4508                         chapters.psz_name += '+';
4509                     chapters.psz_name += ' ';
4510                     char *psz_tmp_utf8 = ToUTF8( UTFstring( name ) );
4511                     chapters.psz_name += psz_tmp_utf8;
4512                     chapters.b_user_display = true;
4513
4514                     msg_Dbg( &sys.demuxer, "|   |   |   |   |    + ChapterString '%s'", psz_tmp_utf8 );
4515                     free( psz_tmp_utf8 );
4516                 }
4517                 else if( MKV_IS_ID( l, KaxChapterLanguage ) )
4518                 {
4519                     KaxChapterLanguage &lang =*(KaxChapterLanguage*)l;
4520                     const char *psz = string( lang ).c_str();
4521
4522                     msg_Dbg( &sys.demuxer, "|   |   |   |   |    + ChapterLanguage '%s'", psz );
4523                 }
4524                 else if( MKV_IS_ID( l, KaxChapterCountry ) )
4525                 {
4526                     KaxChapterCountry &ct =*(KaxChapterCountry*)l;
4527                     const char *psz = string( ct ).c_str();
4528
4529                     msg_Dbg( &sys.demuxer, "|   |   |   |   |    + ChapterCountry '%s'", psz );
4530                 }
4531             }
4532         }
4533         else if( MKV_IS_ID( l, KaxChapterProcess ) )
4534         {
4535             msg_Dbg( &sys.demuxer, "|   |   |   |   + ChapterProcess" );
4536
4537             KaxChapterProcess *cp = static_cast<KaxChapterProcess *>(l);
4538             chapter_codec_cmds_c *p_ccodec = NULL;
4539
4540             for( j = 0; j < cp->ListSize(); j++ )
4541             {
4542                 EbmlElement *k= (*cp)[j];
4543
4544                 if( MKV_IS_ID( k, KaxChapterProcessCodecID ) )
4545                 {
4546                     KaxChapterProcessCodecID *p_codec_id = static_cast<KaxChapterProcessCodecID*>( k );
4547                     if ( uint32(*p_codec_id) == 0 )
4548                         p_ccodec = new matroska_script_codec_c( sys );
4549                     else if ( uint32(*p_codec_id) == 1 )
4550                         p_ccodec = new dvd_chapter_codec_c( sys );
4551                     break;
4552                 }
4553             }
4554
4555             if ( p_ccodec != NULL )
4556             {
4557                 for( j = 0; j < cp->ListSize(); j++ )
4558                 {
4559                     EbmlElement *k= (*cp)[j];
4560
4561                     if( MKV_IS_ID( k, KaxChapterProcessPrivate ) )
4562                     {
4563                         KaxChapterProcessPrivate * p_private = static_cast<KaxChapterProcessPrivate*>( k );
4564                         p_ccodec->SetPrivate( *p_private );
4565                     }
4566                     else if( MKV_IS_ID( k, KaxChapterProcessCommand ) )
4567                     {
4568                         p_ccodec->AddCommand( *static_cast<KaxChapterProcessCommand*>( k ) );
4569                     }
4570                 }
4571                 chapters.codecs.push_back( p_ccodec );
4572             }
4573         }
4574         else if( MKV_IS_ID( l, KaxChapterAtom ) )
4575         {
4576             chapter_item_c *new_sub_chapter = new chapter_item_c();
4577             ParseChapterAtom( i_level+1, static_cast<KaxChapterAtom *>(l), *new_sub_chapter );
4578             new_sub_chapter->psz_parent = &chapters;
4579             chapters.sub_chapters.push_back( new_sub_chapter );
4580         }
4581     }
4582 }
4583
4584 /*****************************************************************************
4585  * ParseChapters:
4586  *****************************************************************************/
4587 void matroska_segment_c::ParseChapters( KaxChapters *chapters )
4588 {
4589     EbmlElement *el;
4590     size_t i;
4591     int i_upper_level = 0;
4592     mtime_t i_dur;
4593
4594     /* Master elements */
4595     chapters->Read( es, chapters->Generic().Context, i_upper_level, el, true );
4596
4597     for( i = 0; i < chapters->ListSize(); i++ )
4598     {
4599         EbmlElement *l = (*chapters)[i];
4600
4601         if( MKV_IS_ID( l, KaxEditionEntry ) )
4602         {
4603             chapter_edition_c *p_edition = new chapter_edition_c();
4604             
4605             EbmlMaster *E = static_cast<EbmlMaster *>(l );
4606             size_t j;
4607             msg_Dbg( &sys.demuxer, "|   |   + EditionEntry" );
4608             for( j = 0; j < E->ListSize(); j++ )
4609             {
4610                 EbmlElement *l = (*E)[j];
4611
4612                 if( MKV_IS_ID( l, KaxChapterAtom ) )
4613                 {
4614                     chapter_item_c *new_sub_chapter = new chapter_item_c();
4615                     ParseChapterAtom( 0, static_cast<KaxChapterAtom *>(l), *new_sub_chapter );
4616                     p_edition->sub_chapters.push_back( new_sub_chapter );
4617                 }
4618                 else if( MKV_IS_ID( l, KaxEditionUID ) )
4619                 {
4620                     p_edition->i_uid = uint64(*static_cast<KaxEditionUID *>( l ));
4621                 }
4622                 else if( MKV_IS_ID( l, KaxEditionFlagOrdered ) )
4623                 {
4624                     p_edition->b_ordered = config_GetInt( &sys.demuxer, "mkv-use-ordered-chapters" ) ? (uint8(*static_cast<KaxEditionFlagOrdered *>( l )) != 0) : 0;
4625                 }
4626                 else if( MKV_IS_ID( l, KaxEditionFlagDefault ) )
4627                 {
4628                     if (uint8(*static_cast<KaxEditionFlagDefault *>( l )) != 0)
4629                         i_default_edition = stored_editions.size();
4630                 }
4631                 else
4632                 {
4633                     msg_Dbg( &sys.demuxer, "|   |   |   + Unknown (%s)", typeid(*l).name() );
4634                 }
4635             }
4636             stored_editions.push_back( p_edition );
4637         }
4638         else
4639         {
4640             msg_Dbg( &sys.demuxer, "|   |   + Unknown (%s)", typeid(*l).name() );
4641         }
4642     }
4643
4644     for( i = 0; i < stored_editions.size(); i++ )
4645     {
4646         stored_editions[i]->RefreshChapters( );
4647     }
4648     
4649     if ( stored_editions.size() != 0 && stored_editions[i_default_edition]->b_ordered )
4650     {
4651         /* update the duration of the segment according to the sum of all sub chapters */
4652         i_dur = stored_editions[i_default_edition]->Duration() / I64C(1000);
4653         if (i_dur > 0)
4654             i_duration = i_dur;
4655     }
4656 }
4657
4658 void matroska_segment_c::ParseCluster( )
4659 {
4660     EbmlElement *el;
4661     EbmlMaster  *m;
4662     unsigned int i;
4663     int i_upper_level = 0;
4664
4665     /* Master elements */
4666     m = static_cast<EbmlMaster *>( cluster );
4667     m->Read( es, cluster->Generic().Context, i_upper_level, el, true );
4668
4669     for( i = 0; i < m->ListSize(); i++ )
4670     {
4671         EbmlElement *l = (*m)[i];
4672
4673         if( MKV_IS_ID( l, KaxClusterTimecode ) )
4674         {
4675             KaxClusterTimecode &ctc = *(KaxClusterTimecode*)l;
4676
4677             cluster->InitTimecode( uint64( ctc ), i_timescale );
4678             break;
4679         }
4680     }
4681
4682     i_start_time = cluster->GlobalTimecode() / 1000;
4683 }
4684
4685 /*****************************************************************************
4686  * InformationCreate:
4687  *****************************************************************************/
4688 void matroska_segment_c::InformationCreate( )
4689 {
4690     size_t      i_track;
4691
4692     sys.meta = vlc_meta_New();
4693
4694     if( psz_title )
4695     {
4696         vlc_meta_Add( sys.meta, VLC_META_TITLE, psz_title );
4697     }
4698     if( psz_date_utc )
4699     {
4700         vlc_meta_Add( sys.meta, VLC_META_DATE, psz_date_utc );
4701     }
4702     if( psz_segment_filename )
4703     {
4704         vlc_meta_Add( sys.meta, _("Segment filename"), psz_segment_filename );
4705     }
4706     if( psz_muxing_application )
4707     {
4708         vlc_meta_Add( sys.meta, _("Muxing application"), psz_muxing_application );
4709     }
4710     if( psz_writing_application )
4711     {
4712         vlc_meta_Add( sys.meta, _("Writing application"), psz_writing_application );
4713     }
4714
4715     for( i_track = 0; i_track < tracks.size(); i_track++ )
4716     {
4717         mkv_track_t *tk = tracks[i_track];
4718         vlc_meta_t *mtk = vlc_meta_New();
4719
4720         sys.meta->track = (vlc_meta_t**)realloc( sys.meta->track,
4721                                                     sizeof( vlc_meta_t * ) * ( sys.meta->i_track + 1 ) );
4722         sys.meta->track[sys.meta->i_track++] = mtk;
4723
4724         if( tk->fmt.psz_description )
4725         {
4726             vlc_meta_Add( sys.meta, VLC_META_DESCRIPTION, tk->fmt.psz_description );
4727         }
4728         if( tk->psz_codec_name )
4729         {
4730             vlc_meta_Add( sys.meta, VLC_META_CODEC_NAME, tk->psz_codec_name );
4731         }
4732         if( tk->psz_codec_settings )
4733         {
4734             vlc_meta_Add( sys.meta, VLC_META_SETTING, tk->psz_codec_settings );
4735         }
4736         if( tk->psz_codec_info_url )
4737         {
4738             vlc_meta_Add( sys.meta, VLC_META_CODEC_DESCRIPTION, tk->psz_codec_info_url );
4739         }
4740         if( tk->psz_codec_download_url )
4741         {
4742             vlc_meta_Add( sys.meta, VLC_META_URL, tk->psz_codec_download_url );
4743         }
4744     }
4745
4746     if( i_tags_position >= 0 )
4747     {
4748         vlc_bool_t b_seekable;
4749
4750         stream_Control( sys.demuxer.s, STREAM_CAN_FASTSEEK, &b_seekable );
4751         if( b_seekable )
4752         {
4753             LoadTags( );
4754         }
4755     }
4756 }
4757
4758
4759 /*****************************************************************************
4760  * Divers
4761  *****************************************************************************/
4762
4763 void matroska_segment_c::IndexAppendCluster( KaxCluster *cluster )
4764 {
4765 #define idx p_indexes[i_index]
4766     idx.i_track       = -1;
4767     idx.i_block_number= -1;
4768     idx.i_position    = cluster->GetElementPosition();
4769     idx.i_time        = -1;
4770     idx.b_key         = VLC_TRUE;
4771
4772     i_index++;
4773     if( i_index >= i_index_max )
4774     {
4775         i_index_max += 1024;
4776         p_indexes = (mkv_index_t*)realloc( p_indexes, sizeof( mkv_index_t ) * i_index_max );
4777     }
4778 #undef idx
4779 }
4780
4781 void chapter_edition_c::RefreshChapters( )
4782 {
4783     chapter_item_c::RefreshChapters( b_ordered, -1 );
4784     b_display_seekpoint = false;
4785 }
4786
4787 int64_t chapter_item_c::RefreshChapters( bool b_ordered, int64_t i_prev_user_time )
4788 {
4789     int64_t i_user_time = i_prev_user_time;
4790     
4791     // first the sub-chapters, and then ourself
4792     std::vector<chapter_item_c*>::iterator index = sub_chapters.begin();
4793     while ( index != sub_chapters.end() )
4794     {
4795         i_user_time = (*index)->RefreshChapters( b_ordered, i_user_time );
4796         index++;
4797     }
4798
4799     if ( b_ordered )
4800     {
4801         // the ordered chapters always start at zero
4802         if ( i_prev_user_time == -1 )
4803         {
4804             if ( i_user_time == -1 )
4805                 i_user_time = 0;
4806             i_prev_user_time = 0;
4807         }
4808
4809         i_user_start_time = i_prev_user_time;
4810         if ( i_end_time != -1 && i_user_time == i_prev_user_time )
4811         {
4812             i_user_end_time = i_user_start_time - i_start_time + i_end_time;
4813         }
4814         else
4815         {
4816             i_user_end_time = i_user_time;
4817         }
4818     }
4819     else
4820     {
4821         if ( sub_chapters.begin() != sub_chapters.end() )
4822             std::sort( sub_chapters.begin(), sub_chapters.end(), chapter_item_c::CompareTimecode );
4823         i_user_start_time = i_start_time;
4824         if ( i_end_time != -1 )
4825             i_user_end_time = i_end_time;
4826         else if ( i_user_time != -1 )
4827             i_user_end_time = i_user_time;
4828         else
4829             i_user_end_time = i_user_start_time;
4830     }
4831
4832     return i_user_end_time;
4833 }
4834
4835 mtime_t chapter_edition_c::Duration() const
4836 {
4837     mtime_t i_result = 0;
4838     
4839     if ( sub_chapters.size() )
4840     {
4841         std::vector<chapter_item_c*>::const_iterator index = sub_chapters.end();
4842         index--;
4843         i_result = (*index)->i_user_end_time;
4844     }
4845     
4846     return i_result;
4847 }
4848
4849 chapter_item_c * chapter_edition_c::FindTimecode( mtime_t i_timecode, const chapter_item_c * p_current )
4850 {
4851     if ( !b_ordered )
4852         p_current = NULL;
4853     bool b_found_current = false;
4854     return chapter_item_c::FindTimecode( i_timecode, p_current, b_found_current );
4855 }
4856
4857 chapter_item_c *chapter_item_c::FindTimecode( mtime_t i_user_timecode, const chapter_item_c * p_current, bool & b_found )
4858 {
4859     chapter_item_c *psz_result = NULL;
4860
4861     if ( p_current == this )
4862         b_found = true;
4863
4864     if ( i_user_timecode >= i_user_start_time && 
4865         ( i_user_timecode < i_user_end_time || 
4866           ( i_user_start_time == i_user_end_time && i_user_timecode == i_user_end_time )))
4867     {
4868         std::vector<chapter_item_c*>::iterator index = sub_chapters.begin();
4869         while ( index != sub_chapters.end() && ((p_current == NULL && psz_result == NULL) || (p_current != NULL && (!b_found || psz_result == NULL))))
4870         {
4871             psz_result = (*index)->FindTimecode( i_user_timecode, p_current, b_found );
4872             index++;
4873         }
4874         
4875         if ( psz_result == NULL )
4876             psz_result = this;
4877     }
4878
4879     return psz_result;
4880 }
4881
4882 bool chapter_item_c::ParentOf( const chapter_item_c & item ) const
4883 {
4884     if ( &item == this )
4885         return true;
4886
4887     std::vector<chapter_item_c*>::const_iterator index = sub_chapters.begin();
4888     while ( index != sub_chapters.end() )
4889     {
4890         if ( (*index)->ParentOf( item ) )
4891             return true;
4892         index++;
4893     }
4894
4895     return false;
4896 }
4897
4898 void demux_sys_t::PreloadFamily( const matroska_segment_c & of_segment )
4899 {
4900     for (size_t i=0; i<opened_segments.size(); i++)
4901     {
4902         opened_segments[i]->PreloadFamily( of_segment );
4903     }
4904 }
4905 bool matroska_segment_c::PreloadFamily( const matroska_segment_c & of_segment )
4906 {
4907     if ( b_preloaded )
4908         return false;
4909
4910     for (size_t i=0; i<families.size(); i++)
4911     {
4912         for (size_t j=0; j<of_segment.families.size(); j++)
4913         {
4914             if ( *(families[i]) == *(of_segment.families[j]) )
4915                 return Preload( );
4916         }
4917     }
4918
4919     return false;
4920 }
4921
4922 // preload all the linked segments for all preloaded segments
4923 void demux_sys_t::PreloadLinked( matroska_segment_c *p_segment )
4924 {
4925     size_t i_preloaded, i, j;
4926     virtual_segment_c *p_seg;
4927
4928     p_current_segment = VirtualFromSegments( p_segment );
4929     
4930     used_segments.push_back( p_current_segment );
4931
4932     // create all the other virtual segments of the family
4933     do {
4934         i_preloaded = 0;
4935         for ( i=0; i< opened_segments.size(); i++ )
4936         {
4937             if ( opened_segments[i]->b_preloaded && !IsUsedSegment( *opened_segments[i] ) )
4938             {
4939                 p_seg = VirtualFromSegments( opened_segments[i] );
4940                 used_segments.push_back( p_seg );
4941                 i_preloaded++;
4942             }
4943         }
4944     } while ( i_preloaded ); // worst case: will stop when all segments are found as family related
4945
4946     // publish all editions of all usable segment
4947     for ( i=0; i< used_segments.size(); i++ )
4948     {
4949         p_seg = used_segments[i];
4950         if ( p_seg->p_editions != NULL )
4951         {
4952             std::string sz_name;
4953             input_title_t *p_title = vlc_input_title_New();
4954             p_seg->i_sys_title = i;
4955             int i_chapters;
4956
4957             // TODO use a name for each edition, let the TITLE deal with a codec name
4958             for ( j=0; j<p_seg->p_editions->size(); j++ )
4959             {
4960                 if ( p_title->psz_name == NULL )
4961                 {
4962                     sz_name = (*p_seg->p_editions)[j]->GetMainName();
4963                     if ( sz_name != "" )
4964                         p_title->psz_name = strdup( sz_name.c_str() );
4965                 }
4966
4967                 chapter_edition_c *p_edition = (*p_seg->p_editions)[j];
4968
4969                 i_chapters = 0;
4970                 p_edition->PublishChapters( *p_title, i_chapters, 0 );
4971             }
4972
4973             // create a name if there is none
4974             if ( p_title->psz_name == NULL )
4975             {
4976                 sz_name = N_("Segment ");
4977                 char psz_str[6];
4978                 sprintf( psz_str, "%d", (int)i );
4979                 sz_name += psz_str;
4980                 p_title->psz_name = strdup( sz_name.c_str() );
4981             }
4982
4983             titles.push_back( p_title );
4984         }
4985     }
4986
4987     // TODO decide which segment should be first used (VMG for DVD)
4988 }
4989
4990 bool demux_sys_t::IsUsedSegment( matroska_segment_c &segment ) const
4991 {
4992     for ( size_t i=0; i< used_segments.size(); i++ )
4993     {
4994         if ( used_segments[i]->FindUID( *segment.p_segment_uid ) )
4995             return true;
4996     }
4997     return false;
4998 }
4999
5000 virtual_segment_c *demux_sys_t::VirtualFromSegments( matroska_segment_c *p_segment ) const
5001 {
5002     size_t i_preloaded, i;
5003
5004     virtual_segment_c *p_result = new virtual_segment_c( p_segment );
5005
5006     // fill our current virtual segment with all hard linked segments
5007     do {
5008         i_preloaded = 0;
5009         for ( i=0; i< opened_segments.size(); i++ )
5010         {
5011             i_preloaded += p_result->AddSegment( opened_segments[i] );
5012         }
5013     } while ( i_preloaded ); // worst case: will stop when all segments are found as linked
5014
5015     p_result->Sort( );
5016
5017     p_result->PreloadLinked( );
5018
5019     p_result->PrepareChapters( );
5020
5021     return p_result;
5022 }
5023
5024 bool demux_sys_t::PreparePlayback( virtual_segment_c *p_new_segment )
5025 {
5026     if ( p_new_segment != NULL && p_new_segment != p_current_segment )
5027     {
5028         if ( p_current_segment != NULL && p_current_segment->Segment() != NULL )
5029             p_current_segment->Segment()->UnSelect();
5030
5031         p_current_segment = p_new_segment;
5032         i_current_title = p_new_segment->i_sys_title;
5033     }
5034
5035     p_current_segment->LoadCues();
5036     f_duration = p_current_segment->Duration();
5037
5038     /* add information */
5039     p_current_segment->Segment()->InformationCreate( );
5040
5041     p_current_segment->Segment()->Select( 0 );
5042
5043     return true;
5044 }
5045
5046 void demux_sys_t::JumpTo( virtual_segment_c & vsegment, chapter_item_c * p_chapter )
5047 {
5048     // if the segment is not part of the current segment, select the new one
5049     if ( &vsegment != p_current_segment )
5050     {
5051         PreparePlayback( &vsegment );
5052     }
5053
5054     if ( p_chapter != NULL )
5055     {
5056         if ( !p_chapter->Enter( true ) )
5057         {
5058             // jump to the location in the found segment
5059             vsegment.Seek( demuxer, p_chapter->i_user_start_time, -1, p_chapter );
5060         }
5061     }
5062     
5063 }
5064
5065 bool matroska_segment_c::CompareSegmentUIDs( const matroska_segment_c * p_item_a, const matroska_segment_c * p_item_b )
5066 {
5067     if ( p_item_a == NULL || p_item_b == NULL )
5068         return false;
5069
5070     EbmlBinary * p_itema = (EbmlBinary *)(p_item_a->p_segment_uid);
5071     if ( p_item_b->p_prev_segment_uid != NULL && *p_itema == *p_item_b->p_prev_segment_uid )
5072         return true;
5073
5074     p_itema = (EbmlBinary *)(&p_item_a->p_next_segment_uid);
5075     if ( p_item_b->p_segment_uid != NULL && *p_itema == *p_item_b->p_segment_uid )
5076         return true;
5077
5078     if ( p_item_b->p_prev_segment_uid != NULL && *p_itema == *p_item_b->p_prev_segment_uid )
5079         return true;
5080
5081     return false;
5082 }
5083
5084 bool matroska_segment_c::Preload( )
5085 {
5086     if ( b_preloaded )
5087         return false;
5088
5089     EbmlElement *el = NULL;
5090
5091     ep->Reset( &sys.demuxer );
5092
5093     while( ( el = ep->Get() ) != NULL )
5094     {
5095         if( MKV_IS_ID( el, KaxInfo ) )
5096         {
5097             ParseInfo( static_cast<KaxInfo*>( el ) );
5098         }
5099         else if( MKV_IS_ID( el, KaxTracks ) )
5100         {
5101             ParseTracks( static_cast<KaxTracks*>( el ) );
5102         }
5103         else if( MKV_IS_ID( el, KaxSeekHead ) )
5104         {
5105             ParseSeekHead( static_cast<KaxSeekHead*>( el ) );
5106         }
5107         else if( MKV_IS_ID( el, KaxCues ) )
5108         {
5109             msg_Dbg( &sys.demuxer, "|   + Cues" );
5110         }
5111         else if( MKV_IS_ID( el, KaxCluster ) )
5112         {
5113             msg_Dbg( &sys.demuxer, "|   + Cluster" );
5114
5115             cluster = (KaxCluster*)el;
5116
5117             i_cluster_pos = i_start_pos = cluster->GetElementPosition();
5118             ParseCluster( );
5119
5120             ep->Down();
5121             /* stop parsing the stream */
5122             break;
5123         }
5124         else if( MKV_IS_ID( el, KaxAttachments ) )
5125         {
5126             msg_Dbg( &sys.demuxer, "|   + Attachments FIXME (but probably never supported)" );
5127         }
5128         else if( MKV_IS_ID( el, KaxChapters ) )
5129         {
5130             msg_Dbg( &sys.demuxer, "|   + Chapters" );
5131             ParseChapters( static_cast<KaxChapters*>( el ) );
5132         }
5133         else if( MKV_IS_ID( el, KaxTag ) )
5134         {
5135             msg_Dbg( &sys.demuxer, "|   + Tags FIXME TODO" );
5136         }
5137         else
5138         {
5139             msg_Dbg( &sys.demuxer, "|   + Unknown (%s)", typeid(*el).name() );
5140         }
5141     }
5142
5143     b_preloaded = true;
5144
5145     return true;
5146 }
5147
5148 matroska_segment_c *demux_sys_t::FindSegment( const EbmlBinary & uid ) const
5149 {
5150     for (size_t i=0; i<opened_segments.size(); i++)
5151     {
5152         if ( *opened_segments[i]->p_segment_uid == uid )
5153             return opened_segments[i];
5154     }
5155     return NULL;
5156 }
5157
5158 chapter_item_c *demux_sys_t::BrowseCodecPrivate( unsigned int codec_id, 
5159                                         bool (*match)(const chapter_codec_cmds_c &data, const void *p_cookie, size_t i_cookie_size ), 
5160                                         const void *p_cookie, 
5161                                         size_t i_cookie_size, 
5162                                         virtual_segment_c * &p_segment_found )
5163 {
5164     chapter_item_c *p_result = NULL;
5165     for (size_t i=0; i<used_segments.size(); i++)
5166     {
5167         p_result = used_segments[i]->BrowseCodecPrivate( codec_id, match, p_cookie, i_cookie_size );
5168         if ( p_result != NULL )
5169         {
5170             p_segment_found = used_segments[i];
5171             break;
5172         }
5173     }
5174     return p_result;
5175 }
5176
5177 chapter_item_c *demux_sys_t::FindChapter( int64_t i_find_uid, virtual_segment_c * & p_segment_found )
5178 {
5179     chapter_item_c *p_result = NULL;
5180     for (size_t i=0; i<used_segments.size(); i++)
5181     {
5182         p_result = used_segments[i]->FindChapter( i_find_uid );
5183         if ( p_result != NULL )
5184         {
5185             p_segment_found = used_segments[i];
5186             break;
5187         }
5188     }
5189     return p_result;
5190 }
5191
5192 void virtual_segment_c::Sort()
5193 {
5194     // keep the current segment index
5195     matroska_segment_c *p_segment = linked_segments[i_current_segment];
5196
5197     std::sort( linked_segments.begin(), linked_segments.end(), matroska_segment_c::CompareSegmentUIDs );
5198
5199     for ( i_current_segment=0; i_current_segment<linked_segments.size(); i_current_segment++)
5200         if ( linked_segments[i_current_segment] == p_segment )
5201             break;
5202 }
5203
5204 size_t virtual_segment_c::AddSegment( matroska_segment_c *p_segment )
5205 {
5206     size_t i;
5207     // check if it's not already in here
5208     for ( i=0; i<linked_segments.size(); i++ )
5209     {
5210         if ( *p_segment->p_segment_uid == *linked_segments[i]->p_segment_uid )
5211             return 0;
5212     }
5213
5214     // find possible mates
5215     for ( i=0; i<linked_uids.size(); i++ )
5216     {
5217         if (   (p_segment->p_segment_uid != NULL && *p_segment->p_segment_uid == linked_uids[i])
5218             || (p_segment->p_prev_segment_uid != NULL && *p_segment->p_prev_segment_uid == linked_uids[i])
5219             || (p_segment->p_next_segment_uid !=NULL && *p_segment->p_next_segment_uid == linked_uids[i]) )
5220         {
5221             linked_segments.push_back( p_segment );
5222
5223             AppendUID( p_segment->p_prev_segment_uid );
5224             AppendUID( p_segment->p_next_segment_uid );
5225
5226             return 1;
5227         }
5228     }
5229     return 0;
5230 }
5231
5232 void virtual_segment_c::PreloadLinked( )
5233 {
5234     for ( size_t i=0; i<linked_segments.size(); i++ )
5235     {
5236         linked_segments[i]->Preload( );
5237     }
5238     i_current_edition = linked_segments[0]->i_default_edition;
5239 }
5240
5241 mtime_t virtual_segment_c::Duration() const
5242 {
5243     mtime_t i_duration;
5244     if ( linked_segments.size() == 0 )
5245         i_duration = 0;
5246     else {
5247         matroska_segment_c *p_last_segment = linked_segments[linked_segments.size()-1];
5248 //        p_last_segment->ParseCluster( );
5249
5250         i_duration = p_last_segment->i_start_time / 1000 + p_last_segment->i_duration;
5251     }
5252     return i_duration;
5253 }
5254
5255 void virtual_segment_c::LoadCues( )
5256 {
5257     for ( size_t i=0; i<linked_segments.size(); i++ )
5258     {
5259         linked_segments[i]->LoadCues();
5260     }
5261 }
5262
5263 void virtual_segment_c::AppendUID( const EbmlBinary * p_UID )
5264 {
5265     if ( p_UID == NULL )
5266         return;
5267     if ( p_UID->GetBuffer() == NULL )
5268         return;
5269
5270     for (size_t i=0; i<linked_uids.size(); i++)
5271     {
5272         if ( *p_UID == linked_uids[i] )
5273             return;
5274     }
5275     linked_uids.push_back( *(KaxSegmentUID*)(p_UID) );
5276 }
5277
5278 void matroska_segment_c::Seek( mtime_t i_date, mtime_t i_time_offset )
5279 {
5280     KaxBlock    *block;
5281     int         i_track_skipping;
5282     int64_t     i_block_duration;
5283     int64_t     i_block_ref1;
5284     int64_t     i_block_ref2;
5285     size_t      i_track;
5286     int64_t     i_seek_position = i_start_pos;
5287     int64_t     i_seek_time = i_start_time;
5288
5289     if ( i_index > 0 )
5290     {
5291         int i_idx = 0;
5292
5293         for( ; i_idx < i_index; i_idx++ )
5294         {
5295             if( p_indexes[i_idx].i_time + i_time_offset > i_date )
5296             {
5297                 break;
5298             }
5299         }
5300
5301         if( i_idx > 0 )
5302         {
5303             i_idx--;
5304         }
5305
5306         i_seek_position = p_indexes[i_idx].i_position;
5307         i_seek_time = p_indexes[i_idx].i_time;
5308     }
5309
5310     msg_Dbg( &sys.demuxer, "seek got "I64Fd" (%d%%)",
5311                 i_seek_time, (int)( 100 * i_seek_position / stream_Size( sys.demuxer.s ) ) );
5312
5313     es.I_O().setFilePointer( i_seek_position, seek_beginning );
5314
5315     delete ep;
5316     ep = new EbmlParser( &es, segment, &sys.demuxer );
5317     cluster = NULL;
5318
5319     sys.i_start_pts = i_date;
5320
5321     es_out_Control( sys.demuxer.out, ES_OUT_RESET_PCR );
5322
5323     /* now parse until key frame */
5324     i_track_skipping = 0;
5325     for( i_track = 0; i_track < tracks.size(); i_track++ )
5326     {
5327         if( tracks[i_track]->fmt.i_cat == VIDEO_ES )
5328         {
5329             tracks[i_track]->b_search_keyframe = VLC_TRUE;
5330             i_track_skipping++;
5331         }
5332         es_out_Control( sys.demuxer.out, ES_OUT_SET_NEXT_DISPLAY_TIME, tracks[i_track]->p_es, i_date );
5333     }
5334
5335
5336     while( i_track_skipping > 0 )
5337     {
5338         if( BlockGet( block, &i_block_ref1, &i_block_ref2, &i_block_duration ) )
5339         {
5340             msg_Warn( &sys.demuxer, "cannot get block EOF?" );
5341
5342             return;
5343         }
5344         ep->Down();
5345
5346         for( i_track = 0; i_track < tracks.size(); i_track++ )
5347         {
5348             if( tracks[i_track]->i_number == block->TrackNum() )
5349             {
5350                 break;
5351             }
5352         }
5353
5354         sys.i_pts = (sys.i_chapter_time + block->GlobalTimecode()) / (mtime_t) 1000;
5355
5356         if( i_track < tracks.size() )
5357         {
5358            if( sys.i_pts >= sys.i_start_pts )
5359             {
5360                 cluster = static_cast<KaxCluster*>(ep->UnGet( i_block_pos, i_cluster_pos ));
5361                 i_track_skipping = 0;
5362             }
5363             else if( tracks[i_track]->fmt.i_cat == VIDEO_ES )
5364             {
5365                 if( i_block_ref1 == 0 && tracks[i_track]->b_search_keyframe )
5366                 {
5367                     tracks[i_track]->b_search_keyframe = VLC_FALSE;
5368                     i_track_skipping--;
5369                 }
5370                 if( !tracks[i_track]->b_search_keyframe )
5371                 {
5372                     BlockDecode( &sys.demuxer, block, sys.i_pts, 0, i_block_ref1 >= 0 || i_block_ref2 > 0 );
5373                 }
5374             } 
5375         }
5376
5377         delete block;
5378     }
5379 }
5380
5381 void virtual_segment_c::Seek( demux_t & demuxer, mtime_t i_date, mtime_t i_time_offset, chapter_item_c *psz_chapter )
5382 {
5383     demux_sys_t *p_sys = demuxer.p_sys;
5384     size_t i;
5385
5386     // find the actual time for an ordered edition
5387     if ( psz_chapter == NULL )
5388     {
5389         if ( Edition() && Edition()->b_ordered )
5390         {
5391             /* 1st, we need to know in which chapter we are */
5392             psz_chapter = (*p_editions)[i_current_edition]->FindTimecode( i_date, psz_current_chapter );
5393         }
5394     }
5395
5396     if ( psz_chapter != NULL )
5397     {
5398         psz_current_chapter = psz_chapter;
5399         p_sys->i_chapter_time = i_time_offset = psz_chapter->i_user_start_time - psz_chapter->i_start_time;
5400         if ( psz_chapter->i_seekpoint_num > 0 )
5401         {
5402             demuxer.info.i_update |= INPUT_UPDATE_TITLE | INPUT_UPDATE_SEEKPOINT;
5403             demuxer.info.i_title = p_sys->i_current_title = i_sys_title;
5404             demuxer.info.i_seekpoint = psz_chapter->i_seekpoint_num - 1;
5405         }
5406     }
5407
5408     // find the best matching segment
5409     for ( i=0; i<linked_segments.size(); i++ )
5410     {
5411         if ( i_date < linked_segments[i]->i_start_time )
5412             break;
5413     }
5414
5415     if ( i > 0 )
5416         i--;
5417
5418     if ( i_current_segment != i  )
5419     {
5420         linked_segments[i_current_segment]->UnSelect();
5421         linked_segments[i]->Select( i_date );
5422         i_current_segment = i;
5423     }
5424
5425     linked_segments[i]->Seek( i_date, i_time_offset );
5426 }
5427
5428 void chapter_codec_cmds_c::AddCommand( const KaxChapterProcessCommand & command )
5429 {
5430     size_t i;
5431
5432     uint32 codec_time = uint32(-1);
5433     for( i = 0; i < command.ListSize(); i++ )
5434     {
5435         const EbmlElement *k = command[i];
5436
5437         if( MKV_IS_ID( k, KaxChapterProcessTime ) )
5438         {
5439             codec_time = uint32( *static_cast<const KaxChapterProcessTime*>( k ) );
5440             break;
5441         }
5442     }
5443
5444     for( i = 0; i < command.ListSize(); i++ )
5445     {
5446         const EbmlElement *k = command[i];
5447
5448         if( MKV_IS_ID( k, KaxChapterProcessData ) )
5449         {
5450             KaxChapterProcessData *p_data =  new KaxChapterProcessData( *static_cast<const KaxChapterProcessData*>( k ) );
5451             switch ( codec_time )
5452             {
5453             case 0:
5454                 during_cmds.push_back( p_data );
5455                 break;
5456             case 1:
5457                 enter_cmds.push_back( p_data );
5458                 break;
5459             case 2:
5460                 leave_cmds.push_back( p_data );
5461                 break;
5462             default:
5463                 delete p_data;
5464             }
5465         }
5466     }
5467 }
5468
5469 bool chapter_item_c::Enter( bool b_do_subs )
5470 {
5471     bool f_result = false;
5472     std::vector<chapter_codec_cmds_c*>::iterator index = codecs.begin();
5473     while ( index != codecs.end() )
5474     {
5475         f_result |= (*index)->Enter();
5476         index++;
5477     }
5478
5479     if ( b_do_subs )
5480     {
5481         // sub chapters
5482         std::vector<chapter_item_c*>::iterator index_ = sub_chapters.begin();
5483         while ( index_ != sub_chapters.end() )
5484         {
5485             f_result |= (*index_)->Enter( true );
5486             index_++;
5487         }
5488     }
5489     return f_result;
5490 }
5491
5492 bool chapter_item_c::Leave( bool b_do_subs )
5493 {
5494     bool f_result = false;
5495     b_is_leaving = true;
5496     std::vector<chapter_codec_cmds_c*>::iterator index = codecs.begin();
5497     while ( index != codecs.end() )
5498     {
5499         f_result |= (*index)->Leave();
5500         index++;
5501     }
5502
5503     if ( b_do_subs )
5504     {
5505         // sub chapters
5506         std::vector<chapter_item_c*>::iterator index_ = sub_chapters.begin();
5507         while ( index_ != sub_chapters.end() )
5508         {
5509             f_result |= (*index_)->Leave( true );
5510             index_++;
5511         }
5512     }
5513     b_is_leaving = false;
5514     return f_result;
5515 }
5516
5517 bool chapter_item_c::EnterAndLeave( chapter_item_c *p_item, bool b_final_enter )
5518 {
5519     chapter_item_c *p_common_parent = p_item;
5520
5521     // leave, up to a common parent
5522     while ( p_common_parent != NULL && !p_common_parent->ParentOf( *this ) )
5523     {
5524         if ( !p_common_parent->b_is_leaving && p_common_parent->Leave( false ) )
5525             return true;
5526         p_common_parent = p_common_parent->psz_parent;
5527     }
5528
5529     // enter from the parent to <this>
5530     if ( p_common_parent != NULL )
5531     {
5532         do
5533         {
5534             if ( p_common_parent == this )
5535                 return Enter( true );
5536
5537             for ( size_t i = 0; i<p_common_parent->sub_chapters.size(); i++ )
5538             {
5539                 if ( p_common_parent->sub_chapters[i]->ParentOf( *this ) )
5540                 {
5541                     p_common_parent = p_common_parent->sub_chapters[i];
5542                     if ( p_common_parent != this )
5543                         if ( p_common_parent->Enter( false ) )
5544                             return true;
5545
5546                     break;
5547                 }
5548             }
5549         } while ( 1 );
5550     }
5551
5552     if ( b_final_enter )
5553         return Enter( true );
5554     else
5555         return false;
5556 }
5557
5558 bool dvd_chapter_codec_c::Enter()
5559 {
5560     bool f_result = false;
5561     std::vector<KaxChapterProcessData*>::iterator index = enter_cmds.begin();
5562     while ( index != enter_cmds.end() )
5563     {
5564         if ( (*index)->GetSize() )
5565         {
5566             binary *p_data = (*index)->GetBuffer();
5567             size_t i_size = *p_data++;
5568             // avoid reading too much from the buffer
5569             i_size = min( i_size, ((*index)->GetSize() - 1) >> 3 );
5570             for ( ; i_size > 0; i_size--, p_data += 8 )
5571             {
5572                 msg_Dbg( &sys.demuxer, "Matroska DVD enter command" );
5573                 f_result |= sys.dvd_interpretor.Interpret( p_data );
5574             }
5575         }
5576         index++;
5577     }
5578     return f_result;
5579 }
5580
5581 bool dvd_chapter_codec_c::Leave()
5582 {
5583     bool f_result = false;
5584     std::vector<KaxChapterProcessData*>::iterator index = leave_cmds.begin();
5585     while ( index != leave_cmds.end() )
5586     {
5587         if ( (*index)->GetSize() )
5588         {
5589             binary *p_data = (*index)->GetBuffer();
5590             size_t i_size = *p_data++;
5591             // avoid reading too much from the buffer
5592             i_size = min( i_size, ((*index)->GetSize() - 1) >> 3 );
5593             for ( ; i_size > 0; i_size--, p_data += 8 )
5594             {
5595                 msg_Dbg( &sys.demuxer, "Matroska DVD leave command" );
5596                 f_result |= sys.dvd_interpretor.Interpret( p_data );
5597             }
5598         }
5599         index++;
5600     }
5601     return f_result;
5602 }
5603
5604 // see http://www.dvd-replica.com/DVD/vmcmdset.php for a description of DVD commands
5605 bool dvd_command_interpretor_c::Interpret( const binary * p_command, size_t i_size )
5606 {
5607     if ( i_size != 8 )
5608         return false;
5609
5610     virtual_segment_c *p_segment = NULL;
5611     chapter_item_c *p_chapter = NULL;
5612     bool f_result = false;
5613     uint16 i_command = ( p_command[0] << 8 ) + p_command[1];
5614
5615     // handle register tests if there are some
5616     if ( (i_command & 0xF0) != 0 )
5617     {
5618         bool b_test_positive = true;//(i_command & CMD_DVD_IF_NOT) == 0;
5619         bool b_test_value    = (i_command & CMD_DVD_TEST_VALUE) != 0;
5620         uint8 i_test = i_command & 0x70;
5621         uint16 i_value;
5622
5623         // see http://dvd.sourceforge.net/dvdinfo/vmi.html
5624         uint8  i_cr1;
5625         uint16 i_cr2;
5626         switch ( i_command >> 12 )
5627         {
5628         default:
5629             i_cr1 = p_command[3];
5630             i_cr2 = (p_command[4] << 8) + p_command[5];
5631             break;
5632         case 3:
5633         case 4:
5634         case 5:
5635             i_cr1 = p_command[6];
5636             i_cr2 = p_command[7];
5637             b_test_value = false;
5638             break;
5639         case 6:
5640         case 7:
5641             if ( ((p_command[1] >> 4) & 0x7) == 0)
5642             {
5643                 i_cr1 = p_command[2];
5644                 i_cr2 = (p_command[6] << 8) + p_command[7];
5645             }
5646             else
5647             {
5648                 i_cr1 = p_command[2];
5649                 i_cr2 = (p_command[6] << 8) + p_command[7];
5650             }
5651             break;
5652         }
5653
5654         if ( b_test_value )
5655             i_value = i_cr2;
5656         else
5657             i_value = GetPRM( i_cr2 );
5658
5659         switch ( i_test )
5660         {
5661         case CMD_DVD_IF_GPREG_EQUAL:
5662             // if equals
5663             msg_Dbg( &sys.demuxer, "IF %s EQUALS %s", GetRegTypeName( false, i_cr1 ).c_str(), GetRegTypeName( b_test_value, i_value ).c_str() );
5664             if (!( GetPRM( i_cr1 ) == i_value ))
5665             {
5666                 b_test_positive = false;
5667             }
5668             break;
5669         case CMD_DVD_IF_GPREG_NOT_EQUAL:
5670             // if not equals
5671             msg_Dbg( &sys.demuxer, "IF %s NOT EQUALS %s", GetRegTypeName( false, i_cr1 ).c_str(), GetRegTypeName( b_test_value, i_value ).c_str() );
5672             if (!( GetPRM( i_cr1 ) != i_value ))
5673             {
5674                 b_test_positive = false;
5675             }
5676             break;
5677         case CMD_DVD_IF_GPREG_INF:
5678             // if inferior
5679             msg_Dbg( &sys.demuxer, "IF %s < %s", GetRegTypeName( false, p_command[3] ).c_str(), GetRegTypeName( b_test_value, i_value ).c_str() );
5680             if (!( GetPRM( i_cr1 ) < i_value ))
5681             {
5682                 b_test_positive = false;
5683             }
5684             break;
5685         case CMD_DVD_IF_GPREG_INF_EQUAL:
5686             // if inferior or equal
5687             msg_Dbg( &sys.demuxer, "IF %s < %s", GetRegTypeName( false, p_command[3] ).c_str(), GetRegTypeName( b_test_value, i_value ).c_str() );
5688             if (!( GetPRM( i_cr1 ) <= i_value ))
5689             {
5690                 b_test_positive = false;
5691             }
5692             break;
5693         case CMD_DVD_IF_GPREG_AND:
5694             // if logical and
5695             msg_Dbg( &sys.demuxer, "IF %s & %s", GetRegTypeName( false, p_command[3] ).c_str(), GetRegTypeName( b_test_value, i_value ).c_str() );
5696             if (!( GetPRM( i_cr1 ) & i_value ))
5697             {
5698                 b_test_positive = false;
5699             }
5700             break;
5701         case CMD_DVD_IF_GPREG_SUP:
5702             // if superior
5703             msg_Dbg( &sys.demuxer, "IF %s >= %s", GetRegTypeName( false, p_command[3] ).c_str(), GetRegTypeName( b_test_value, i_value ).c_str() );
5704             if (!( GetPRM( i_cr1 ) > i_value ))
5705             {
5706                 b_test_positive = false;
5707             }
5708             break;
5709         case CMD_DVD_IF_GPREG_SUP_EQUAL:
5710             // if superior or equal
5711             msg_Dbg( &sys.demuxer, "IF %s >= %s", GetRegTypeName( false, p_command[3] ).c_str(), GetRegTypeName( b_test_value, i_value ).c_str() );
5712             if (!( GetPRM( i_cr1 ) >= i_value ))
5713             {
5714                 b_test_positive = false;
5715             }
5716             break;
5717         }
5718
5719         if ( !b_test_positive )
5720             return false;
5721     }
5722     
5723     // strip the test command
5724     i_command &= 0xFF0F;
5725     
5726     switch ( i_command )
5727     {
5728     case CMD_DVD_NOP:
5729     case CMD_DVD_NOP2:
5730         {
5731             msg_Dbg( &sys.demuxer, "NOP" );
5732             break;
5733         }
5734     case CMD_DVD_BREAK:
5735         {
5736             msg_Dbg( &sys.demuxer, "Break" );
5737             // TODO
5738             break;
5739         }
5740     case CMD_DVD_JUMP_TT:
5741         {
5742             uint8 i_title = p_command[5];
5743             msg_Dbg( &sys.demuxer, "JumpTT %d", i_title );
5744
5745             // find in the ChapProcessPrivate matching this Title level
5746             p_chapter = sys.BrowseCodecPrivate( 1, MatchTitleNumber, &i_title, sizeof(i_title), p_segment );
5747             if ( p_segment != NULL )
5748             {
5749                 sys.JumpTo( *p_segment, p_chapter );
5750                 f_result = true;
5751             }
5752
5753             break;
5754         }
5755     case CMD_DVD_CALLSS_VTSM1:
5756         {
5757             msg_Dbg( &sys.demuxer, "CallSS" );
5758             binary p_type;
5759             switch( (p_command[6] & 0xC0) >> 6 ) {
5760                 case 0:
5761                     p_type = p_command[5] & 0x0F;
5762                     switch ( p_type )
5763                     {
5764                     case 0x00:
5765                         msg_Dbg( &sys.demuxer, "CallSS PGC (rsm_cell %x)", p_command[4]);
5766                         break;
5767                     case 0x02:
5768                         msg_Dbg( &sys.demuxer, "CallSS Title Entry (rsm_cell %x)", p_command[4]);
5769                         break;
5770                     case 0x03:
5771                         msg_Dbg( &sys.demuxer, "CallSS Root Menu (rsm_cell %x)", p_command[4]);
5772                         break;
5773                     case 0x04:
5774                         msg_Dbg( &sys.demuxer, "CallSS Subpicture Menu (rsm_cell %x)", p_command[4]);
5775                         break;
5776                     case 0x05:
5777                         msg_Dbg( &sys.demuxer, "CallSS Audio Menu (rsm_cell %x)", p_command[4]);
5778                         break;
5779                     case 0x06:
5780                         msg_Dbg( &sys.demuxer, "CallSS Angle Menu (rsm_cell %x)", p_command[4]);
5781                         break;
5782                     case 0x07:
5783                         msg_Dbg( &sys.demuxer, "CallSS Chapter Menu (rsm_cell %x)", p_command[4]);
5784                         break;
5785                     default:
5786                         msg_Dbg( &sys.demuxer, "CallSS <unknown> (rsm_cell %x)", p_command[4]);
5787                         break;
5788                     }
5789                     p_chapter = sys.BrowseCodecPrivate( 1, MatchPgcType, &p_type, 1, p_segment );
5790                     if ( p_segment != NULL )
5791                     {
5792                         sys.JumpTo( *p_segment, p_chapter );
5793                         f_result = true;
5794                     }
5795                 break;
5796                 case 1:
5797                     msg_Dbg( &sys.demuxer, "CallSS VMGM (menu %d, rsm_cell %x)", p_command[5] & 0x0F, p_command[4]);
5798                 break;
5799                 case 2:
5800                     msg_Dbg( &sys.demuxer, "CallSS VTSM (menu %d, rsm_cell %x)", p_command[5] & 0x0F, p_command[4]);
5801                 break;
5802                 case 3:
5803                     msg_Dbg( &sys.demuxer, "CallSS VMGM (pgc %d, rsm_cell %x)", (p_command[2] << 8) + p_command[3], p_command[4]);
5804                 break;
5805             }
5806             break;
5807         }
5808     case CMD_DVD_JUMP_SS:
5809         {
5810             msg_Dbg( &sys.demuxer, "JumpSS");
5811             binary p_type;
5812             switch( (p_command[5] & 0xC0) >> 6 ) {
5813                 case 0:
5814                     msg_Dbg( &sys.demuxer, "JumpSS FP");
5815                 break;
5816                 case 1:
5817                     p_type = p_command[5] & 0x0F;
5818                     switch ( p_type )
5819                     {
5820                     case 0x02:
5821                         msg_Dbg( &sys.demuxer, "JumpSS VMGM Title Entry");
5822                         break;
5823                     case 0x03:
5824                         msg_Dbg( &sys.demuxer, "JumpSS VMGM Root Menu");
5825                         break;
5826                     case 0x04:
5827                         msg_Dbg( &sys.demuxer, "JumpSS VMGM Subpicture Menu");
5828                         break;
5829                     case 0x05:
5830                         msg_Dbg( &sys.demuxer, "JumpSS VMGM Audio Menu");
5831                         break;
5832                     case 0x06:
5833                         msg_Dbg( &sys.demuxer, "JumpSS VMGM Angle Menu");
5834                         break;
5835                     case 0x07:
5836                         msg_Dbg( &sys.demuxer, "JumpSS VMGM Chapter Menu");
5837                         break;
5838                     default:
5839                         msg_Dbg( &sys.demuxer, "JumpSS <unknown>");
5840                         break;
5841                     }
5842                     // find the VMG
5843                     p_chapter = sys.BrowseCodecPrivate( 1, MatchIsVMG, NULL, 0, p_segment );
5844                     if ( p_segment != NULL )
5845                     {
5846                         p_chapter = p_segment->BrowseCodecPrivate( 1, MatchPgcType, &p_type, 1 );
5847                         if ( p_chapter != NULL )
5848                         {
5849                             sys.JumpTo( *p_segment, p_chapter );
5850                             f_result = true;
5851                         }
5852                     }
5853                 break;
5854                 case 2:
5855                     p_type = p_command[5] & 0x0F;
5856                     switch ( p_type )
5857                     {
5858                     case 0x02:
5859                         msg_Dbg( &sys.demuxer, "JumpSS VTSM (vts %d, ttn %d) Title Entry", p_command[4], p_command[3]);
5860                         break;
5861                     case 0x03:
5862                         msg_Dbg( &sys.demuxer, "JumpSS VTSM (vts %d, ttn %d) Root Menu", p_command[4], p_command[3]);
5863                         break;
5864                     case 0x04:
5865                         msg_Dbg( &sys.demuxer, "JumpSS VTSM (vts %d, ttn %d) Subpicture Menu", p_command[4], p_command[3]);
5866                         break;
5867                     case 0x05:
5868                         msg_Dbg( &sys.demuxer, "JumpSS VTSM (vts %d, ttn %d) Audio Menu", p_command[4], p_command[3]);
5869                         break;
5870                     case 0x06:
5871                         msg_Dbg( &sys.demuxer, "JumpSS VTSM (vts %d, ttn %d) Angle Menu", p_command[4], p_command[3]);
5872                         break;
5873                     case 0x07:
5874                         msg_Dbg( &sys.demuxer, "JumpSS VTSM (vts %d, ttn %d) Chapter Menu", p_command[4], p_command[3]);
5875                         break;
5876                     default:
5877                         msg_Dbg( &sys.demuxer, "JumpSS VTSM (vts %d, ttn %d) <unknown>", p_command[4], p_command[3]);
5878                         break;
5879                     }
5880
5881                     p_chapter = sys.BrowseCodecPrivate( 1, MatchVTSMNumber, &p_command[4], 1, p_segment );
5882
5883                     if ( p_segment != NULL && p_chapter != NULL )
5884                     {
5885                         // find the title in the VTS
5886                         p_chapter = p_chapter->BrowseCodecPrivate( 1, MatchTitleNumber, &p_command[3], 1 );
5887                         if ( p_chapter != NULL )
5888                         {
5889                             // find the specified menu in the VTSM
5890                             p_chapter = p_segment->BrowseCodecPrivate( 1, MatchPgcType, &p_type, 1 );
5891                             if ( p_chapter != NULL )
5892                             {
5893                                 sys.JumpTo( *p_segment, p_chapter );
5894                                 f_result = true;
5895                             }
5896                         }
5897                         else
5898                             msg_Dbg( &sys.demuxer, "Title (%d) does not exist in this VTS", p_command[3] );
5899                     }
5900                     else
5901                         msg_Dbg( &sys.demuxer, "DVD Domain VTS (%d) not found", p_command[4] );
5902                 break;
5903                 case 3:
5904                     msg_Dbg( &sys.demuxer, "JumpSS VMGM (pgc %d)", (p_command[2] << 8) + p_command[3]);
5905                 break;
5906             }
5907             break;
5908         }
5909     case CMD_DVD_JUMPVTS_PTT:
5910         {
5911             uint8 i_title = p_command[5];
5912             uint8 i_ptt = p_command[3];
5913
5914             msg_Dbg( &sys.demuxer, "JumpVTS Title (%d) PTT (%d)", i_title, i_ptt);
5915
5916             // find the current VTS content segment
5917             p_chapter = sys.p_current_segment->BrowseCodecPrivate( 1, MatchIsDomain, NULL, 0 );
5918             if ( p_chapter != NULL )
5919             {
5920                 int16 i_curr_title = p_chapter->GetTitleNumber( );
5921                 if ( i_curr_title > 0 )
5922                 {
5923                     p_chapter = sys.BrowseCodecPrivate( 1, MatchVTSNumber, &i_curr_title, sizeof(i_curr_title), p_segment );
5924
5925                     if ( p_segment != NULL && p_chapter != NULL )
5926                     {
5927                         // find the title in the VTS
5928                         p_chapter = p_chapter->BrowseCodecPrivate( 1, MatchTitleNumber, &i_title, sizeof(i_title) );
5929                         if ( p_chapter != NULL )
5930                         {
5931                             // find the chapter in the title
5932                             p_chapter = p_chapter->BrowseCodecPrivate( 1, MatchChapterNumber, &i_ptt, sizeof(i_ptt) );
5933                             if ( p_chapter != NULL )
5934                             {
5935                                 sys.JumpTo( *p_segment, p_chapter );
5936                                 f_result = true;
5937                             }
5938                         }
5939                     else
5940                         msg_Dbg( &sys.demuxer, "Title (%d) does not exist in this VTS", i_title );
5941                     }
5942                     else
5943                         msg_Dbg( &sys.demuxer, "DVD Domain VTS (%d) not found", i_curr_title );
5944                 }
5945                 else
5946                     msg_Dbg( &sys.demuxer, "JumpVTS_PTT command found but not in a VTS(M)");
5947             }
5948             else
5949                 msg_Dbg( &sys.demuxer, "JumpVTS_PTT command but the DVD domain wasn't found");
5950             break;
5951         }
5952     case CMD_DVD_SET_GPRMMD:
5953         {
5954             msg_Dbg( &sys.demuxer, "Set GPRMMD [%d]=%d", (p_command[4] << 8) + p_command[5], (p_command[2] << 8) + p_command[3]);
5955             
5956             if ( !SetGPRM( (p_command[4] << 8) + p_command[5], (p_command[2] << 8) + p_command[3] ) )
5957                 msg_Dbg( &sys.demuxer, "Set GPRMMD failed" );
5958             break;
5959         }
5960     case CMD_DVD_LINKPGCN:
5961         {
5962             uint16 i_pgcn = (p_command[6] << 8) + p_command[7];
5963             
5964             msg_Dbg( &sys.demuxer, "Link PGCN(%d)", i_pgcn );
5965             p_chapter = sys.p_current_segment->BrowseCodecPrivate( 1, MatchPgcNumber, &i_pgcn, 2 );
5966             if ( p_chapter != NULL )
5967             {
5968                 if ( !p_chapter->Enter( true ) )
5969                     // jump to the location in the found segment
5970                     sys.p_current_segment->Seek( sys.demuxer, p_chapter->i_user_start_time, -1, p_chapter );
5971
5972                 f_result = true;
5973             }
5974             break;
5975         }
5976     case CMD_DVD_LINKCN:
5977         {
5978             uint8 i_cn = p_command[7];
5979             
5980             p_chapter = sys.p_current_segment->CurrentChapter();
5981
5982             msg_Dbg( &sys.demuxer, "LinkCN (cell %d)", i_cn );
5983             p_chapter = p_chapter->BrowseCodecPrivate( 1, MatchCellNumber, &i_cn, 1 );
5984             if ( p_chapter != NULL )
5985             {
5986                 if ( !p_chapter->Enter( true ) )
5987                     // jump to the location in the found segment
5988                     sys.p_current_segment->Seek( sys.demuxer, p_chapter->i_user_start_time, -1, p_chapter );
5989
5990                 f_result = true;
5991             }
5992             break;
5993         }
5994     case CMD_DVD_GOTO_LINE:
5995         {
5996             msg_Dbg( &sys.demuxer, "GotoLine (%d)", (p_command[6] << 8) + p_command[7] );
5997             // TODO
5998             break;
5999         }
6000     case CMD_DVD_SET_HL_BTNN1:
6001         {
6002             msg_Dbg( &sys.demuxer, "SetHL_BTN (%d)", p_command[4] );
6003             SetSPRM( 0x88, p_command[4] );
6004             break;
6005         }
6006     default:
6007         {
6008             msg_Dbg( &sys.demuxer, "unsupported command : %02X %02X %02X %02X %02X %02X %02X %02X"
6009                      ,p_command[0]
6010                      ,p_command[1]
6011                      ,p_command[2]
6012                      ,p_command[3]
6013                      ,p_command[4]
6014                      ,p_command[5]
6015                      ,p_command[6]
6016                      ,p_command[7]);
6017             break;
6018         }
6019     }
6020
6021     return f_result;
6022 }
6023
6024 bool dvd_command_interpretor_c::MatchIsDomain( const chapter_codec_cmds_c &data, const void *p_cookie, size_t i_cookie_size )
6025 {
6026     return ( data.p_private_data != NULL && data.p_private_data->GetBuffer()[0] == MATROSKA_DVD_LEVEL_SS );
6027 }
6028
6029 bool dvd_command_interpretor_c::MatchIsVMG( const chapter_codec_cmds_c &data, const void *p_cookie, size_t i_cookie_size )
6030 {
6031     if ( data.p_private_data == NULL || data.p_private_data->GetSize() < 2 )
6032         return false;
6033
6034     return ( data.p_private_data->GetBuffer()[0] == MATROSKA_DVD_LEVEL_SS && data.p_private_data->GetBuffer()[1] == 0xC0);
6035 }
6036
6037 bool dvd_command_interpretor_c::MatchVTSNumber( const chapter_codec_cmds_c &data, const void *p_cookie, size_t i_cookie_size )
6038 {
6039     if ( i_cookie_size != 2 || data.p_private_data == NULL || data.p_private_data->GetSize() < 4 )
6040         return false;
6041     
6042     if ( data.p_private_data->GetBuffer()[0] != MATROSKA_DVD_LEVEL_SS || data.p_private_data->GetBuffer()[1] != 0x80 )
6043         return false;
6044
6045     uint16 i_gtitle = (data.p_private_data->GetBuffer()[2] << 8 ) + data.p_private_data->GetBuffer()[3];
6046     uint16 i_title = *(uint16*)p_cookie;
6047
6048     return (i_gtitle == i_title);
6049 }
6050
6051 bool dvd_command_interpretor_c::MatchVTSMNumber( const chapter_codec_cmds_c &data, const void *p_cookie, size_t i_cookie_size )
6052 {
6053     if ( i_cookie_size != 1 || data.p_private_data == NULL || data.p_private_data->GetSize() < 4 )
6054         return false;
6055     
6056     if ( data.p_private_data->GetBuffer()[0] != MATROSKA_DVD_LEVEL_SS || data.p_private_data->GetBuffer()[1] != 0x40 )
6057         return false;
6058
6059     uint8 i_gtitle = data.p_private_data->GetBuffer()[3];
6060     uint8 i_title = *(uint8*)p_cookie;
6061
6062     return (i_gtitle == i_title);
6063 }
6064
6065 bool dvd_command_interpretor_c::MatchTitleNumber( const chapter_codec_cmds_c &data, const void *p_cookie, size_t i_cookie_size )
6066 {
6067     if ( i_cookie_size != 1 || data.p_private_data == NULL || data.p_private_data->GetSize() < 4 )
6068         return false;
6069     
6070     if ( data.p_private_data->GetBuffer()[0] != MATROSKA_DVD_LEVEL_TT )
6071         return false;
6072
6073     uint16 i_gtitle = (data.p_private_data->GetBuffer()[1] << 8 ) + data.p_private_data->GetBuffer()[2];
6074     uint8 i_title = *(uint8*)p_cookie;
6075
6076     return (i_gtitle == i_title);
6077 }
6078
6079 bool dvd_command_interpretor_c::MatchPgcType( const chapter_codec_cmds_c &data, const void *p_cookie, size_t i_cookie_size )
6080 {
6081     if ( i_cookie_size != 1 || data.p_private_data == NULL || data.p_private_data->GetSize() < 8 )
6082         return false;
6083     
6084     if ( data.p_private_data->GetBuffer()[0] != MATROSKA_DVD_LEVEL_PGC )
6085         return false;
6086
6087     uint8 i_pgc_type = data.p_private_data->GetBuffer()[3] & 0x0F;
6088     uint8 i_pgc = *(uint8*)p_cookie;
6089
6090     return (i_pgc_type == i_pgc);
6091 }
6092
6093 bool dvd_command_interpretor_c::MatchPgcNumber( const chapter_codec_cmds_c &data, const void *p_cookie, size_t i_cookie_size )
6094 {
6095     if ( i_cookie_size != 2 || data.p_private_data == NULL || data.p_private_data->GetSize() < 8 )
6096         return false;
6097     
6098     if ( data.p_private_data->GetBuffer()[0] != MATROSKA_DVD_LEVEL_PGC )
6099         return false;
6100
6101     uint16 *i_pgc_n = (uint16 *)p_cookie;
6102     uint16 i_pgc_num = (data.p_private_data->GetBuffer()[1] << 8) + data.p_private_data->GetBuffer()[2];
6103
6104     return (i_pgc_num == *i_pgc_n);
6105 }
6106
6107 bool dvd_command_interpretor_c::MatchChapterNumber( const chapter_codec_cmds_c &data, const void *p_cookie, size_t i_cookie_size )
6108 {
6109     if ( i_cookie_size != 1 || data.p_private_data == NULL || data.p_private_data->GetSize() < 2 )
6110         return false;
6111     
6112     if ( data.p_private_data->GetBuffer()[0] != MATROSKA_DVD_LEVEL_PTT )
6113         return false;
6114
6115     uint8 i_chapter = data.p_private_data->GetBuffer()[1];
6116     uint8 i_ptt = *(uint8*)p_cookie;
6117
6118     return (i_chapter == i_ptt);
6119 }
6120
6121 bool dvd_command_interpretor_c::MatchCellNumber( const chapter_codec_cmds_c &data, const void *p_cookie, size_t i_cookie_size )
6122 {
6123     if ( i_cookie_size != 1 || data.p_private_data == NULL || data.p_private_data->GetSize() < 5 )
6124         return false;
6125     
6126     if ( data.p_private_data->GetBuffer()[0] != MATROSKA_DVD_LEVEL_CN )
6127         return false;
6128
6129     uint8 *i_cell_n = (uint8 *)p_cookie;
6130     uint8 i_cell_num = data.p_private_data->GetBuffer()[3];
6131
6132     return (i_cell_num == *i_cell_n);
6133 }
6134
6135 bool matroska_script_codec_c::Enter()
6136 {
6137     bool f_result = false;
6138     std::vector<KaxChapterProcessData*>::iterator index = enter_cmds.begin();
6139     while ( index != enter_cmds.end() )
6140     {
6141         if ( (*index)->GetSize() )
6142         {
6143             msg_Dbg( &sys.demuxer, "Matroska Script enter command" );
6144             f_result |= interpretor.Interpret( (*index)->GetBuffer(), (*index)->GetSize() );
6145         }
6146         index++;
6147     }
6148     return f_result;
6149 }
6150
6151 bool matroska_script_codec_c::Leave()
6152 {
6153     bool f_result = false;
6154     std::vector<KaxChapterProcessData*>::iterator index = leave_cmds.begin();
6155     while ( index != leave_cmds.end() )
6156     {
6157         if ( (*index)->GetSize() )
6158         {
6159             msg_Dbg( &sys.demuxer, "Matroska Script leave command" );
6160             f_result |= interpretor.Interpret( (*index)->GetBuffer(), (*index)->GetSize() );
6161         }
6162         index++;
6163     }
6164     return f_result;
6165 }
6166
6167 // see http://www.matroska.org/technical/specs/chapters/index.html#mscript 
6168 //  for a description of existing commands
6169 bool matroska_script_interpretor_c::Interpret( const binary * p_command, size_t i_size )
6170 {
6171     bool b_result = false;
6172
6173     char *psz_str = (char*) malloc( i_size + 1 );
6174     memcpy( psz_str, p_command, i_size );
6175     psz_str[ i_size ] = '\0';
6176
6177     std::string sz_command = psz_str;
6178     free( psz_str );
6179
6180     msg_Dbg( &sys.demuxer, "command : %s", sz_command.c_str() );
6181
6182 #if defined(__GNUC__) && (__GNUC__ < 3)
6183     if ( sz_command.compare( CMD_MS_GOTO_AND_PLAY, 0, CMD_MS_GOTO_AND_PLAY.size() ) == 0 )
6184 #else
6185     if ( sz_command.compare( 0, CMD_MS_GOTO_AND_PLAY.size(), CMD_MS_GOTO_AND_PLAY ) == 0 )
6186 #endif
6187     {
6188         size_t i,j;
6189
6190         // find the (
6191         for ( i=CMD_MS_GOTO_AND_PLAY.size(); i<sz_command.size(); i++)
6192         {
6193             if ( sz_command[i] == '(' )
6194             {
6195                 i++;
6196                 break;
6197             }
6198         }
6199         // find the )
6200         for ( j=i; j<sz_command.size(); j++)
6201         {
6202             if ( sz_command[j] == ')' )
6203             {
6204                 i--;
6205                 break;
6206             }
6207         }
6208
6209         std::string st = sz_command.substr( i+1, j-i-1 );
6210         int64_t i_chapter_uid = atoi( st.c_str() );
6211
6212         virtual_segment_c *p_segment;
6213         chapter_item_c *p_chapter = sys.FindChapter( i_chapter_uid, p_segment );
6214
6215         if ( p_chapter == NULL )
6216             msg_Dbg( &sys.demuxer, "Chapter "I64Fd" not found", i_chapter_uid);
6217         else
6218         {
6219             if ( !p_chapter->EnterAndLeave( sys.p_current_segment->CurrentChapter() ) )
6220                 p_segment->Seek( sys.demuxer, p_chapter->i_user_start_time, -1, p_chapter );
6221             b_result = true;
6222         }
6223     }
6224
6225     return b_result;
6226 }
6227
6228 void demux_sys_t::SwapButtons()
6229 {
6230 #ifndef WORDS_BIGENDIAN
6231     uint8_t button, i, j;
6232
6233     for( button = 1; button <= pci_packet.hli.hl_gi.btn_ns; button++) {
6234         btni_t *button_ptr = &(pci_packet.hli.btnit[button-1]);
6235         binary *p_data = (binary*) button_ptr;
6236
6237         uint16 i_x_start = ((p_data[0] & 0x3F) << 4 ) + ( p_data[1] >> 4 );
6238         uint16 i_x_end   = ((p_data[1] & 0x03) << 8 ) + p_data[2];
6239         uint16 i_y_start = ((p_data[3] & 0x3F) << 4 ) + ( p_data[4] >> 4 );
6240         uint16 i_y_end   = ((p_data[4] & 0x03) << 8 ) + p_data[5];
6241         button_ptr->x_start = i_x_start;
6242         button_ptr->x_end   = i_x_end;
6243         button_ptr->y_start = i_y_start;
6244         button_ptr->y_end   = i_y_end;
6245
6246     }
6247     for ( i = 0; i<3; i++ )
6248     {
6249         for ( j = 0; j<2; j++ )
6250         {
6251             pci_packet.hli.btn_colit.btn_coli[i][j] = U32_AT( &pci_packet.hli.btn_colit.btn_coli[i][j] );
6252         }
6253     }
6254 #endif
6255 }