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