mkv.cpp 206 KB
Newer Older
Steve Lhomme's avatar
Steve Lhomme committed
1
2
3
/*****************************************************************************
 * mkv.cpp : matroska demuxer
 *****************************************************************************
4
 * Copyright (C) 2003-2004 the VideoLAN team
Steve Lhomme's avatar
Steve Lhomme committed
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
 * $Id$
 *
 * Authors: Laurent Aimar <fenrir@via.ecp.fr>
 *          Steve Lhomme <steve.lhomme@free.fr>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
 *****************************************************************************/

/*****************************************************************************
 * Preamble
 *****************************************************************************/
#include <stdlib.h>                                      /* malloc(), free() */

#include <vlc/vlc.h>

#ifdef HAVE_TIME_H
#   include <time.h>                                               /* time() */
#endif

#include <vlc/input.h>

#include <codecs.h>                        /* BITMAPINFOHEADER, WAVEFORMATEX */
#include "iso_lang.h"
#include "vlc_meta.h"

#include <iostream>
#include <cassert>
#include <typeinfo>
#include <string>
#include <vector>
47
#include <algorithm>
Steve Lhomme's avatar
Steve Lhomme committed
48
49
50
51
52
53
54
55
56
57
58

#ifdef HAVE_DIRENT_H
#   include <dirent.h>
#endif

/* libebml and matroska */
#include "ebml/EbmlHead.h"
#include "ebml/EbmlSubHead.h"
#include "ebml/EbmlStream.h"
#include "ebml/EbmlContexts.h"
#include "ebml/EbmlVoid.h"
59
#include "ebml/EbmlVersion.h"
Steve Lhomme's avatar
Steve Lhomme committed
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
#include "ebml/StdIOCallback.h"

#include "matroska/KaxAttachments.h"
#include "matroska/KaxBlock.h"
#include "matroska/KaxBlockData.h"
#include "matroska/KaxChapters.h"
#include "matroska/KaxCluster.h"
#include "matroska/KaxClusterData.h"
#include "matroska/KaxContexts.h"
#include "matroska/KaxCues.h"
#include "matroska/KaxCuesData.h"
#include "matroska/KaxInfo.h"
#include "matroska/KaxInfoData.h"
#include "matroska/KaxSeekHead.h"
#include "matroska/KaxSegment.h"
#include "matroska/KaxTag.h"
#include "matroska/KaxTags.h"
#include "matroska/KaxTagMulti.h"
#include "matroska/KaxTracks.h"
#include "matroska/KaxTrackAudio.h"
#include "matroska/KaxTrackVideo.h"
#include "matroska/KaxTrackEntryData.h"
#include "matroska/KaxContentEncoding.h"
83
#include "matroska/KaxVersion.h"
Steve Lhomme's avatar
Steve Lhomme committed
84
85
86

#include "ebml/StdIOCallback.h"

87
88
#include "vlc_keys.h"

Steve Lhomme's avatar
Steve Lhomme committed
89
90
91
92
93
94
95
96
97
98
extern "C" {
   #include "mp4/libmp4.h"
}
#ifdef HAVE_ZLIB_H
#   include <zlib.h>
#endif

#define MATROSKA_COMPRESSION_NONE 0
#define MATROSKA_COMPRESSION_ZLIB 1

99
100
#define MKVD_TIMECODESCALE 1000000

101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#undef ATTRIBUTE_PACKED
#undef PRAGMA_PACK_BEGIN 
#undef PRAGMA_PACK_END

#if defined(__GNUC__)
#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 95)
#define ATTRIBUTE_PACKED __attribute__ ((packed))
#define PRAGMA_PACK 0
#endif
#endif

#if !defined(ATTRIBUTE_PACKED)
#define ATTRIBUTE_PACKED
#define PRAGMA_PACK 1
#endif

#if PRAGMA_PACK
#pragma pack(1)
#endif

/*************************************
*  taken from libdvdnav / libdvdread
**************************************/

/**
 * DVD Time Information.
 */
typedef struct {
  uint8_t hour;
  uint8_t minute;
  uint8_t second;
  uint8_t frame_u; /* The two high bits are the frame rate. */
} ATTRIBUTE_PACKED dvd_time_t;

/**
 * User Operations.
 */
typedef struct {
#ifdef WORDS_BIGENDIAN
141
142
  unsigned char zero                           : 7; /* 25-31 */
  unsigned char video_pres_mode_change         : 1; /* 24 */
143
  
144
145
146
147
148
149
150
151
  unsigned char karaoke_audio_pres_mode_change : 1; /* 23 */
  unsigned char angle_change                   : 1;
  unsigned char subpic_stream_change           : 1;
  unsigned char audio_stream_change            : 1;
  unsigned char pause_on                       : 1;
  unsigned char still_off                      : 1;
  unsigned char button_select_or_activate      : 1;
  unsigned char resume                         : 1; /* 16 */
152
  
153
154
155
156
157
158
159
160
  unsigned char chapter_menu_call              : 1; /* 15 */
  unsigned char angle_menu_call                : 1;
  unsigned char audio_menu_call                : 1;
  unsigned char subpic_menu_call               : 1;
  unsigned char root_menu_call                 : 1;
  unsigned char title_menu_call                : 1;
  unsigned char backward_scan                  : 1;
  unsigned char forward_scan                   : 1; /* 8 */
161
  
162
163
164
165
166
167
168
169
  unsigned char next_pg_search                 : 1; /* 7 */
  unsigned char prev_or_top_pg_search          : 1;
  unsigned char time_or_chapter_search         : 1;
  unsigned char go_up                          : 1;
  unsigned char stop                           : 1;
  unsigned char title_play                     : 1;
  unsigned char chapter_search_or_play         : 1;
  unsigned char title_or_time_play             : 1; /* 0 */
170
#else
171
172
  unsigned char video_pres_mode_change         : 1; /* 24 */
  unsigned char zero                           : 7; /* 25-31 */
173
  
174
175
176
177
178
179
180
181
  unsigned char resume                         : 1; /* 16 */
  unsigned char button_select_or_activate      : 1;
  unsigned char still_off                      : 1;
  unsigned char pause_on                       : 1;
  unsigned char audio_stream_change            : 1;
  unsigned char subpic_stream_change           : 1;
  unsigned char angle_change                   : 1;
  unsigned char karaoke_audio_pres_mode_change : 1; /* 23 */
182
  
183
184
185
186
187
188
189
190
  unsigned char forward_scan                   : 1; /* 8 */
  unsigned char backward_scan                  : 1;
  unsigned char title_menu_call                : 1;
  unsigned char root_menu_call                 : 1;
  unsigned char subpic_menu_call               : 1;
  unsigned char audio_menu_call                : 1;
  unsigned char angle_menu_call                : 1;
  unsigned char chapter_menu_call              : 1; /* 15 */
191
  
192
193
194
195
196
197
198
199
  unsigned char title_or_time_play             : 1; /* 0 */
  unsigned char chapter_search_or_play         : 1;
  unsigned char title_play                     : 1;
  unsigned char stop                           : 1;
  unsigned char go_up                          : 1;
  unsigned char time_or_chapter_search         : 1;
  unsigned char prev_or_top_pg_search          : 1;
  unsigned char next_pg_search                 : 1; /* 7 */
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
#endif
} ATTRIBUTE_PACKED user_ops_t;

/**
 * Type to store per-command data.
 */
typedef struct {
  uint8_t bytes[8];
} ATTRIBUTE_PACKED vm_cmd_t;
#define COMMAND_DATA_SIZE 8

/**
 * PCI General Information 
 */
typedef struct {
  uint32_t nv_pck_lbn;      /**< sector address of this nav pack */
  uint16_t vobu_cat;        /**< 'category' of vobu */
  uint16_t zero1;           /**< reserved */
  user_ops_t vobu_uop_ctl;  /**< UOP of vobu */
  uint32_t vobu_s_ptm;      /**< start presentation time of vobu */
  uint32_t vobu_e_ptm;      /**< end presentation time of vobu */
  uint32_t vobu_se_e_ptm;   /**< end ptm of sequence end in vobu */
  dvd_time_t e_eltm;        /**< Cell elapsed time */
  char vobu_isrc[32];
} ATTRIBUTE_PACKED pci_gi_t;

/**
 * Non Seamless Angle Information
 */
typedef struct {
  uint32_t nsml_agl_dsta[9];  /**< address of destination vobu in AGL_C#n */
} ATTRIBUTE_PACKED nsml_agli_t;

/** 
 * Highlight General Information 
 *
 * For btngrX_dsp_ty the bits have the following meaning:
 * 000b: normal 4/3 only buttons
 * XX1b: wide (16/9) buttons
 * X1Xb: letterbox buttons
 * 1XXb: pan&scan buttons
 */
typedef struct {
  uint16_t hli_ss; /**< status, only low 2 bits 0: no buttons, 1: different 2: equal 3: eual except for button cmds */
  uint32_t hli_s_ptm;              /**< start ptm of hli */
  uint32_t hli_e_ptm;              /**< end ptm of hli */
  uint32_t btn_se_e_ptm;           /**< end ptm of button select */
#ifdef WORDS_BIGENDIAN
  unsigned char zero1 : 2;          /**< reserved */
  unsigned char btngr_ns : 2;       /**< number of button groups 1, 2 or 3 with 36/18/12 buttons */
  unsigned char zero2 : 1;          /**< reserved */
  unsigned char btngr1_dsp_ty : 3;  /**< display type of subpic stream for button group 1 */
  unsigned char zero3 : 1;          /**< reserved */
  unsigned char btngr2_dsp_ty : 3;  /**< display type of subpic stream for button group 2 */
  unsigned char zero4 : 1;          /**< reserved */
  unsigned char btngr3_dsp_ty : 3;  /**< display type of subpic stream for button group 3 */
#else
  unsigned char btngr1_dsp_ty : 3;
  unsigned char zero2 : 1;
  unsigned char btngr_ns : 2;
  unsigned char zero1 : 2;
  unsigned char btngr3_dsp_ty : 3;
  unsigned char zero4 : 1;
  unsigned char btngr2_dsp_ty : 3;
  unsigned char zero3 : 1;
#endif
  uint8_t btn_ofn;     /**< button offset number range 0-255 */
  uint8_t btn_ns;      /**< number of valid buttons  <= 36/18/12 (low 6 bits) */  
  uint8_t nsl_btn_ns;  /**< number of buttons selectable by U_BTNNi (low 6 bits)   nsl_btn_ns <= btn_ns */
  uint8_t zero5;       /**< reserved */
  uint8_t fosl_btnn;   /**< forcedly selected button  (low 6 bits) */
  uint8_t foac_btnn;   /**< forcedly activated button (low 6 bits) */
} ATTRIBUTE_PACKED hl_gi_t;


/** 
 * Button Color Information Table 
 * Each entry beeing a 32bit word that contains the color indexs and alpha
 * values to use.  They are all represented by 4 bit number and stored
 * like this [Ci3, Ci2, Ci1, Ci0, A3, A2, A1, A0].   The actual palette
 * that the indexes reference is in the PGC.
 * @TODO split the uint32_t into a struct
 */
typedef struct {
  uint32_t btn_coli[3][2];  /**< [button color number-1][select:0/action:1] */
} ATTRIBUTE_PACKED btn_colit_t;

/** 
 * Button Information
 *
 * NOTE: I've had to change the structure from the disk layout to get
 * the packing to work with Sun's Forte C compiler.
 * The 4 and 7 bytes are 'rotated' was: ABC DEF GHIJ  is: ABCG DEFH IJ
 */
typedef struct {
#ifdef WORDS_BIGENDIAN
296
297
298
299
  uint32        btn_coln         : 2;  /**< button color number */
  uint32        x_start          : 10; /**< x start offset within the overlay */
  uint32        zero1            : 2;  /**< reserved */
  uint32        x_end            : 10; /**< x end offset within the overlay */
300

301
302
  uint32        zero3            : 2;  /**< reserved */
  uint32        up               : 6;  /**< button index when pressing up */
303

304
305
306
307
  uint32        auto_action_mode : 2;  /**< 0: no, 1: activated if selected */
  uint32        y_start          : 10; /**< y start offset within the overlay */
  uint32        zero2            : 2;  /**< reserved */
  uint32        y_end            : 10; /**< y end offset within the overlay */
308

309
310
  uint32        zero4            : 2;  /**< reserved */
  uint32        down             : 6;  /**< button index when pressing down */
311
312
313
314
315
  unsigned char zero5            : 2;  /**< reserved */
  unsigned char left             : 6;  /**< button index when pressing left */
  unsigned char zero6            : 2;  /**< reserved */
  unsigned char right            : 6;  /**< button index when pressing right */
#else
316
317
318
319
  uint32        x_end            : 10;
  uint32        zero1            : 2;
  uint32        x_start          : 10;
  uint32        btn_coln         : 2;
320

321
322
  uint32        up               : 6;
  uint32        zero3            : 2;
323

324
325
326
327
  uint32        y_end            : 10;
  uint32        zero2            : 2;
  uint32        y_start          : 10;
  uint32        auto_action_mode : 2;
328

329
330
  uint32        down             : 6;
  uint32        zero4            : 2;
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
  unsigned char left             : 6;
  unsigned char zero5            : 2;
  unsigned char right            : 6;
  unsigned char zero6            : 2;
#endif
  vm_cmd_t cmd;
} ATTRIBUTE_PACKED btni_t;

/**
 * Highlight Information 
 */
typedef struct {
  hl_gi_t     hl_gi;
  btn_colit_t btn_colit;
  btni_t      btnit[36];
} ATTRIBUTE_PACKED hli_t;

/**
 * PCI packet
 */
typedef struct {
  pci_gi_t    pci_gi;
  nsml_agli_t nsml_agli;
  hli_t       hli;
  uint8_t     zero1[189];
} ATTRIBUTE_PACKED pci_t;


#if PRAGMA_PACK
#pragma pack()
#endif
////////////////////////////////////////////////////////////////////////////////////////////////////////////////


Steve Lhomme's avatar
Steve Lhomme committed
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
/**
 * What's between a directory and a filename?
 */
#if defined( WIN32 )
    #define DIRECTORY_SEPARATOR '\\'
#else
    #define DIRECTORY_SEPARATOR '/'
#endif

using namespace LIBMATROSKA_NAMESPACE;
using namespace std;

/*****************************************************************************
 * Module descriptor
 *****************************************************************************/
static int  Open ( vlc_object_t * );
static void Close( vlc_object_t * );

vlc_module_begin();
384
    set_shortname( "Matroska" );
Steve Lhomme's avatar
Steve Lhomme committed
385
386
387
388
389
390
    set_description( _("Matroska stream demuxer" ) );
    set_capability( "demux2", 50 );
    set_callbacks( Open, Close );
    set_category( CAT_INPUT );
    set_subcategory( SUBCAT_INPUT_DEMUX );

391
392
    add_bool( "mkv-use-ordered-chapters", 1, NULL,
            N_("Ordered chapters"),
393
            N_("Play ordered chapters as specified in the segment."), VLC_TRUE );
394
395
396

    add_bool( "mkv-use-chapter-codec", 1, NULL,
            N_("Chapter codecs"),
397
            N_("Use chapter codecs found in the segment."), VLC_TRUE );
398
399

    add_bool( "mkv-seek-percent", 0, NULL,
400
401
            N_("Seek based on percent not time."),
            N_("Seek based on percent not time."), VLC_TRUE );
Steve Lhomme's avatar
Steve Lhomme committed
402

403
404
    add_bool( "mkv-use-dummy", 0, NULL,
            N_("Dummy Elements"),
405
            N_("Read and discard unknown EBML elements (not good for broken files)."), VLC_TRUE );
406

Steve Lhomme's avatar
Steve Lhomme committed
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
    add_shortcut( "mka" );
    add_shortcut( "mkv" );
vlc_module_end();

/*****************************************************************************
 * Local prototypes
 *****************************************************************************/
#ifdef HAVE_ZLIB_H
block_t *block_zlib_decompress( vlc_object_t *p_this, block_t *p_in_block ) {
    int result, dstsize, n;
    unsigned char *dst;
    block_t *p_block;
    z_stream d_stream;

    d_stream.zalloc = (alloc_func)0;
    d_stream.zfree = (free_func)0;
    d_stream.opaque = (voidpf)0;
    result = inflateInit(&d_stream);
    if( result != Z_OK )
    {
        msg_Dbg( p_this, "inflateInit() failed. Result: %d", result );
        return NULL;
    }

    d_stream.next_in = (Bytef *)p_in_block->p_buffer;
    d_stream.avail_in = p_in_block->i_buffer;
    n = 0;
    p_block = block_New( p_this, 0 );
    dst = NULL;
    do
    {
        n++;
        p_block = block_Realloc( p_block, 0, n * 1000 );
        dst = (unsigned char *)p_block->p_buffer;
        d_stream.next_out = (Bytef *)&dst[(n - 1) * 1000];
        d_stream.avail_out = 1000;
        result = inflate(&d_stream, Z_NO_FLUSH);
        if( ( result != Z_OK ) && ( result != Z_STREAM_END ) )
        {
            msg_Dbg( p_this, "Zlib decompression failed. Result: %d", result );
            return NULL;
        }
    }
    while( ( d_stream.avail_out == 0 ) && ( d_stream.avail_in != 0 ) &&
           ( result != Z_STREAM_END ) );

    dstsize = d_stream.total_out;
    inflateEnd( &d_stream );

    p_block = block_Realloc( p_block, 0, dstsize );
    p_block->i_buffer = dstsize;
    block_Release( p_in_block );

    return p_block;
}
#endif

/**
 * Helper function to print the mkv parse tree
 */
467
static void MkvTree( demux_t & demuxer, int i_level, char *psz_format, ... )
Steve Lhomme's avatar
Steve Lhomme committed
468
469
470
471
{
    va_list args;
    if( i_level > 9 )
    {
472
        msg_Err( &demuxer, "too deep tree" );
Steve Lhomme's avatar
Steve Lhomme committed
473
474
475
476
477
478
479
480
481
        return;
    }
    va_start( args, psz_format );
    static char *psz_foo = "|   |   |   |   |   |   |   |   |   |";
    char *psz_foo2 = (char*)malloc( ( i_level * 4 + 3 + strlen( psz_format ) ) * sizeof(char) );
    strncpy( psz_foo2, psz_foo, 4 * i_level );
    psz_foo2[ 4 * i_level ] = '+';
    psz_foo2[ 4 * i_level + 1 ] = ' ';
    strcpy( &psz_foo2[ 4 * i_level + 2 ], psz_format );
482
    __msg_GenericVa( VLC_OBJECT(&demuxer), VLC_MSG_DBG, "mkv", psz_foo2, args );
Steve Lhomme's avatar
Steve Lhomme committed
483
484
485
486
487
488
489
490
491
492
493
494
    free( psz_foo2 );
    va_end( args );
}
    
/*****************************************************************************
 * Stream managment
 *****************************************************************************/
class vlc_stream_io_callback: public IOCallback
{
  private:
    stream_t       *s;
    vlc_bool_t     mb_eof;
495
    vlc_bool_t     b_owner;
Steve Lhomme's avatar
Steve Lhomme committed
496
497

  public:
498
499
500
501
502
503
504
    vlc_stream_io_callback( stream_t *, vlc_bool_t );

    virtual ~vlc_stream_io_callback()
    {
        if( b_owner )
            stream_Delete( s );
    }
Steve Lhomme's avatar
Steve Lhomme committed
505
506
507
508
509
510
511
512
513
514
515
516
517
518

    virtual uint32   read            ( void *p_buffer, size_t i_size);
    virtual void     setFilePointer  ( int64_t i_offset, seek_mode mode = seek_beginning );
    virtual size_t   write           ( const void *p_buffer, size_t i_size);
    virtual uint64   getFilePointer  ( void );
    virtual void     close           ( void );
};

/*****************************************************************************
 * Ebml Stream parser
 *****************************************************************************/
class EbmlParser
{
  public:
519
    EbmlParser( EbmlStream *es, EbmlElement *el_start, demux_t *p_demux );
520
    virtual ~EbmlParser( void );
Steve Lhomme's avatar
Steve Lhomme committed
521
522
523

    void Up( void );
    void Down( void );
524
    void Reset( demux_t *p_demux );
Steve Lhomme's avatar
Steve Lhomme committed
525
526
    EbmlElement *Get( void );
    void        Keep( void );
527
    EbmlElement *UnGet( uint64 i_block_pos, uint64 i_cluster_pos );
Steve Lhomme's avatar
Steve Lhomme committed
528
529
530
531
532
533
534

    int GetLevel( void );

  private:
    EbmlStream  *m_es;
    int         mi_level;
    EbmlElement *m_el[10];
535
    int64_t      mi_remain_size[10];
Steve Lhomme's avatar
Steve Lhomme committed
536
537
538
539
540

    EbmlElement *m_got;

    int         mi_user_level;
    vlc_bool_t  mb_keep;
541
    vlc_bool_t  mb_dummy;
Steve Lhomme's avatar
Steve Lhomme committed
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
};


/*****************************************************************************
 * Some functions to manipulate memory
 *****************************************************************************/
#define GetFOURCC( p )  __GetFOURCC( (uint8_t*)p )
static vlc_fourcc_t __GetFOURCC( uint8_t *p )
{
    return VLC_FOURCC( p[0], p[1], p[2], p[3] );
}

/*****************************************************************************
 * definitions of structures and functions used by this plugins
 *****************************************************************************/
typedef struct
{
Steve Lhomme's avatar
Steve Lhomme committed
559
560
561
    vlc_bool_t   b_default;
    vlc_bool_t   b_enabled;
    unsigned int i_number;
Steve Lhomme's avatar
Steve Lhomme committed
562

Steve Lhomme's avatar
Steve Lhomme committed
563
564
    int          i_extra_data;
    uint8_t      *p_extra_data;
Steve Lhomme's avatar
Steve Lhomme committed
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582

    char         *psz_codec;

    uint64_t     i_default_duration;
    float        f_timecodescale;

    /* video */
    es_format_t fmt;
    float       f_fps;
    es_out_id_t *p_es;

    vlc_bool_t      b_inited;
    /* data to be send first */
    int             i_data_init;
    uint8_t         *p_data_init;

    /* hack : it's for seek */
    vlc_bool_t      b_search_keyframe;
583
    vlc_bool_t      b_silent;
Steve Lhomme's avatar
Steve Lhomme committed
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606

    /* informative */
    char         *psz_codec_name;
    char         *psz_codec_settings;
    char         *psz_codec_info_url;
    char         *psz_codec_download_url;
    
    /* encryption/compression */
    int           i_compression_type;

} mkv_track_t;

typedef struct
{
    int     i_track;
    int     i_block_number;

    int64_t i_position;
    int64_t i_time;

    vlc_bool_t b_key;
} mkv_index_t;

607
608
class demux_sys_t;

609
610
611
612
613
614
615
616
const binary MATROSKA_DVD_LEVEL_SS   = 0x30;
const binary MATROSKA_DVD_LEVEL_LU   = 0x2A;
const binary MATROSKA_DVD_LEVEL_TT   = 0x28;
const binary MATROSKA_DVD_LEVEL_PGC  = 0x20;
const binary MATROSKA_DVD_LEVEL_PG   = 0x18;
const binary MATROSKA_DVD_LEVEL_PTT  = 0x10;
const binary MATROSKA_DVD_LEVEL_CN   = 0x08;

617
class chapter_codec_cmds_c
618
{
619
public:
620
    chapter_codec_cmds_c( demux_sys_t & demuxer, int codec_id = -1)
Steve Lhomme's avatar
Steve Lhomme committed
621
622
    :p_private_data(NULL)
    ,i_codec_id( codec_id )
623
    ,sys( demuxer )
624
625
    {}
        
Steve Lhomme's avatar
Steve Lhomme committed
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
    virtual ~chapter_codec_cmds_c() 
    {
        delete p_private_data;
        std::vector<KaxChapterProcessData*>::iterator indexe = enter_cmds.begin();
        while ( indexe != enter_cmds.end() )
        {
            delete (*indexe);
            indexe++;
        }
        std::vector<KaxChapterProcessData*>::iterator indexl = leave_cmds.begin();
        while ( indexl != leave_cmds.end() )
        {
            delete (*indexl);
            indexl++;
        }
        std::vector<KaxChapterProcessData*>::iterator indexd = during_cmds.begin();
        while ( indexd != during_cmds.end() )
        {
            delete (*indexd);
            indexd++;
        }
    }
Steve Lhomme's avatar
Steve Lhomme committed
648

649
650
    void SetPrivate( const KaxChapterProcessPrivate & private_data )
    {
Steve Lhomme's avatar
Steve Lhomme committed
651
        p_private_data = new KaxChapterProcessPrivate( private_data );
652
653
654
    }

    void AddCommand( const KaxChapterProcessCommand & command );
655
    
656
657
658
    /// \return wether the codec has seeked in the files or not
    virtual bool Enter() { return false; }
    virtual bool Leave() { return false; }
659
    virtual std::string GetCodecName( bool f_for_title = false ) const { return ""; }
660
    virtual int16 GetTitleNumber() { return -1; }
661

Steve Lhomme's avatar
Steve Lhomme committed
662
    KaxChapterProcessPrivate *p_private_data;
663

664
protected:
Steve Lhomme's avatar
Steve Lhomme committed
665
666
667
    std::vector<KaxChapterProcessData*> enter_cmds;
    std::vector<KaxChapterProcessData*> during_cmds;
    std::vector<KaxChapterProcessData*> leave_cmds;
668
669

    int i_codec_id;
670
    demux_sys_t & sys;
671
672
};

673
class dvd_command_interpretor_c
674
{
Steve Lhomme's avatar
Steve Lhomme committed
675
public:
676
677
    dvd_command_interpretor_c( demux_sys_t & demuxer )
    :sys( demuxer )
678
    {
679
680
681
682
683
684
685
686
687
        memset( p_PRMs, 0, sizeof(p_PRMs) );
        p_PRMs[ 0x80 + 1 ] = 15;
        p_PRMs[ 0x80 + 2 ] = 62;
        p_PRMs[ 0x80 + 3 ] = 1;
        p_PRMs[ 0x80 + 4 ] = 1;
        p_PRMs[ 0x80 + 7 ] = 1;
        p_PRMs[ 0x80 + 8 ] = 1;
        p_PRMs[ 0x80 + 16 ] = 0xFFFFu;
        p_PRMs[ 0x80 + 18 ] = 0xFFFFu;
688
689
    }
    
690
691
    bool Interpret( const binary * p_command, size_t i_size = 8 );
    
692
693
694
695
696
697
698
    uint16 GetPRM( size_t index ) const
    {
        if ( index < 256 )
            return p_PRMs[ index ];
        else return 0;
    }

Steve Lhomme's avatar
Steve Lhomme committed
699
700
701
    uint16 GetGPRM( size_t index ) const
    {
        if ( index >= 0 && index < 16 )
702
            return p_PRMs[ index ];
Steve Lhomme's avatar
Steve Lhomme committed
703
704
        else return 0;
    }
705

Steve Lhomme's avatar
Steve Lhomme committed
706
707
708
    uint16 GetSPRM( size_t index ) const
    {
        // 21,22,23 reserved for future use
709
710
        if ( index >= 0x80 && index < 0x95 )
            return p_PRMs[ index ];
Steve Lhomme's avatar
Steve Lhomme committed
711
712
        else return 0;
    }
713

714
715
716
717
718
719
720
721
722
723
    bool SetPRM( size_t index, uint16 value )
    {
        if ( index >= 0 && index < 16 )
        {
            p_PRMs[ index ] = value;
            return true;
        }
        return false;
    }
    
Steve Lhomme's avatar
Steve Lhomme committed
724
725
726
    bool SetGPRM( size_t index, uint16 value )
    {
        if ( index >= 0 && index < 16 )
727
        {
728
            p_PRMs[ index ] = value;
Steve Lhomme's avatar
Steve Lhomme committed
729
            return true;
730
        }
Steve Lhomme's avatar
Steve Lhomme committed
731
732
        return false;
    }
733

Steve Lhomme's avatar
Steve Lhomme committed
734
735
    bool SetSPRM( size_t index, uint16 value )
    {
736
        if ( index > 0x80 && index <= 0x8D && index != 0x8C )
737
        {
738
            p_PRMs[ index ] = value;
Steve Lhomme's avatar
Steve Lhomme committed
739
            return true;
740
        }
Steve Lhomme's avatar
Steve Lhomme committed
741
742
        return false;
    }
743

744
protected:
745
746
747
748
    std::string GetRegTypeName( bool b_value, uint16 value ) const
    {
        std::string result;
        char s_value[6], s_reg_value[6];
749
        sprintf( s_value, "%.5d", value );
750
751
752
753
754
755
756
757
758

        if ( b_value )
        {
            result = "value (";
            result += s_value;
            result += ")";
        }
        else if ( value < 0x80 )
        {
759
            sprintf( s_reg_value, "%.5d", GetPRM( value ) );
760
761
762
763
764
765
766
767
            result = "GPreg[";
            result += s_value;
            result += "] (";
            result += s_reg_value;
            result += ")";
        }
        else
        {
768
            sprintf( s_reg_value, "%.5d", GetPRM( value ) );
769
770
771
772
773
774
775
776
777
778
            result = "SPreg[";
            result += s_value;
            result += "] (";
            result += s_reg_value;
            result += ")";
        }
        return result;
    }

    uint16       p_PRMs[256];
779
780
781
    demux_sys_t  & sys;
    
    // DVD command IDs
782
783
784
785

    // Tests
    // wether it's a comparison on the value or register
    static const uint16 CMD_DVD_TEST_VALUE          = 0x80;
786
787
788
789
790
791
792
    static const uint16 CMD_DVD_IF_GPREG_AND        = (1 << 4);
    static const uint16 CMD_DVD_IF_GPREG_EQUAL      = (2 << 4);
    static const uint16 CMD_DVD_IF_GPREG_NOT_EQUAL  = (3 << 4);
    static const uint16 CMD_DVD_IF_GPREG_SUP_EQUAL  = (4 << 4);
    static const uint16 CMD_DVD_IF_GPREG_SUP        = (5 << 4);
    static const uint16 CMD_DVD_IF_GPREG_INF_EQUAL  = (6 << 4);
    static const uint16 CMD_DVD_IF_GPREG_INF        = (7 << 4);
793
794
795
796
797
798
799
800
801
802
803
    
    static const uint16 CMD_DVD_NOP                    = 0x0000;
    static const uint16 CMD_DVD_GOTO_LINE              = 0x0001;
    static const uint16 CMD_DVD_BREAK                  = 0x0002;
    // Links
    static const uint16 CMD_DVD_NOP2                   = 0x2001;
    static const uint16 CMD_DVD_LINKPGCN               = 0x2004;
    static const uint16 CMD_DVD_LINKPGN                = 0x2006;
    static const uint16 CMD_DVD_LINKCN                 = 0x2007;
    static const uint16 CMD_DVD_JUMP_TT                = 0x3002;
    static const uint16 CMD_DVD_JUMPVTS_TT             = 0x3003;
804
    static const uint16 CMD_DVD_JUMPVTS_PTT            = 0x3005;
805
806
807
808
809
    static const uint16 CMD_DVD_JUMP_SS                = 0x3006;
    static const uint16 CMD_DVD_CALLSS_VTSM1           = 0x3008;
    //
    static const uint16 CMD_DVD_SET_HL_BTNN2           = 0x4600;
    static const uint16 CMD_DVD_SET_HL_BTNN_LINKPGCN1  = 0x4604;
810
    static const uint16 CMD_DVD_SET_STREAM             = 0x5100;
811
812
813
814
815
816
817
818
819
820
821
    static const uint16 CMD_DVD_SET_GPRMMD             = 0x5300;
    static const uint16 CMD_DVD_SET_HL_BTNN1           = 0x5600;
    static const uint16 CMD_DVD_SET_HL_BTNN_LINKPGCN2  = 0x5604;
    static const uint16 CMD_DVD_SET_HL_BTNN_LINKCN     = 0x5607;
    // Operations
    static const uint16 CMD_DVD_MOV_SPREG_PREG         = 0x6100;
    static const uint16 CMD_DVD_GPREG_MOV_VALUE        = 0x7100;
    static const uint16 CMD_DVD_SUB_GPREG              = 0x7400;
    static const uint16 CMD_DVD_MULT_GPREG             = 0x7500;
    static const uint16 CMD_DVD_GPREG_DIV_VALUE        = 0x7600;
    static const uint16 CMD_DVD_GPREG_AND_VALUE        = 0x7900;
822
823
    
    // callbacks when browsing inside CodecPrivate
824
    static bool MatchIsDomain     ( const chapter_codec_cmds_c &data, const void *p_cookie, size_t i_cookie_size );
825
    static bool MatchIsVMG        ( const chapter_codec_cmds_c &data, const void *p_cookie, size_t i_cookie_size );
826
    static bool MatchVTSNumber    ( const chapter_codec_cmds_c &data, const void *p_cookie, size_t i_cookie_size );
827
    static bool MatchVTSMNumber   ( const chapter_codec_cmds_c &data, const void *p_cookie, size_t i_cookie_size );
828
829
830
831
832
    static bool MatchTitleNumber  ( const chapter_codec_cmds_c &data, const void *p_cookie, size_t i_cookie_size );
    static bool MatchPgcType      ( const chapter_codec_cmds_c &data, const void *p_cookie, size_t i_cookie_size );
    static bool MatchPgcNumber    ( const chapter_codec_cmds_c &data, const void *p_cookie, size_t i_cookie_size );
    static bool MatchChapterNumber( const chapter_codec_cmds_c &data, const void *p_cookie, size_t i_cookie_size );
    static bool MatchCellNumber   ( const chapter_codec_cmds_c &data, const void *p_cookie, size_t i_cookie_size );
833
834
};

835
class dvd_chapter_codec_c : public chapter_codec_cmds_c
836
{
Steve Lhomme's avatar
Steve Lhomme committed
837
public:
838
    dvd_chapter_codec_c( demux_sys_t & sys )
839
    :chapter_codec_cmds_c( sys, 1 )
840
841
    {}

Steve Lhomme's avatar
Steve Lhomme committed
842
843
    bool Enter();
    bool Leave();
844
    std::string GetCodecName( bool f_for_title = false ) const;
845
    int16 GetTitleNumber();
846
847
};

848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
class matroska_script_interpretor_c
{
public:
    matroska_script_interpretor_c( demux_sys_t & demuxer )
    :sys( demuxer )
    {}

    bool Interpret( const binary * p_command, size_t i_size );
    
    // DVD command IDs
    static const std::string CMD_MS_GOTO_AND_PLAY;
    
protected:
    demux_sys_t  & sys;
};

const std::string matroska_script_interpretor_c::CMD_MS_GOTO_AND_PLAY = "GotoAndPlay";


867
868
class matroska_script_codec_c : public chapter_codec_cmds_c
{
869
870
public:
    matroska_script_codec_c( demux_sys_t & sys )
871
    :chapter_codec_cmds_c( sys, 0 )
872
873
874
875
876
877
878
879
    ,interpretor( sys )
    {}

    bool Enter();
    bool Leave();

protected:
    matroska_script_interpretor_c interpretor; 
880
881
882
};

class chapter_translation_c
883
884
{
public:
Steve Lhomme's avatar
Steve Lhomme committed
885
886
887
888
889
890
891
892
893
894
    chapter_translation_c()
        :p_translated(NULL)
    {}

    ~chapter_translation_c()
    {
        delete p_translated;
    }

    KaxChapterTranslateID  *p_translated;
895
896
897
898
    unsigned int           codec_id;
    std::vector<uint64_t>  editions;
};

899
class chapter_item_c
900
901
{
public:
902
    chapter_item_c()
903
904
905
906
907
    :i_start_time(0)
    ,i_end_time(-1)
    ,i_user_start_time(-1)
    ,i_user_end_time(-1)
    ,i_seekpoint_num(-1)
908
    ,b_display_seekpoint(true)
909
    ,b_user_display(false)
910
    ,psz_parent(NULL)
911
    ,b_is_leaving(false)
912
    {}
913

914
    virtual ~chapter_item_c()
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
    {
        std::vector<chapter_codec_cmds_c*>::iterator index = codecs.begin();
        while ( index != codecs.end() )
        {
            delete (*index);
            index++;
        }
        std::vector<chapter_item_c*>::iterator index_ = sub_chapters.begin();
        while ( index_ != sub_chapters.end() )
        {
            delete (*index_);
            index_++;
        }
    }

930
    int64_t RefreshChapters( bool b_ordered, int64_t i_prev_user_time );
931
    int PublishChapters( input_title_t & title, int & i_user_chapters, int i_level = 0 );
932
    virtual chapter_item_c * FindTimecode( mtime_t i_timecode, const chapter_item_c * p_current, bool & b_found );
933
    void Append( const chapter_item_c & edition );
934
    chapter_item_c * FindChapter( int64_t i_find_uid );
935
    virtual chapter_item_c *BrowseCodecPrivate( unsigned int codec_id, 
936
937
938
                                    bool (*match)(const chapter_codec_cmds_c &data, const void *p_cookie, size_t i_cookie_size ), 
                                    const void *p_cookie, 
                                    size_t i_cookie_size );
939
    std::string                 GetCodecName( bool f_for_title = false ) const;
940
    bool                        ParentOf( const chapter_item_c & item ) const;
941
    int16                       GetTitleNumber( ) const;
942
    
943
    int64_t                     i_start_time, i_end_time;
944
    int64_t                     i_user_start_time, i_user_end_time; /* the time in the stream when an edition is ordered */
945
    std::vector<chapter_item_c*> sub_chapters;
946
    int                         i_seekpoint_num;
947
    int64_t                     i_uid;
948
    bool                        b_display_seekpoint;
949
    bool                        b_user_display;
950
    std::string                 psz_name;
951
    chapter_item_c              *psz_parent;
952
    bool                        b_is_leaving;
953
    
954
    std::vector<chapter_codec_cmds_c*> codecs;
955

956
    bool operator<( const chapter_item_c & item ) const
957
958
959
    {
        return ( i_user_start_time < item.i_user_start_time || (i_user_start_time == item.i_user_start_time && i_user_end_time < item.i_user_end_time) );
    }
960

961
962
    bool Enter( bool b_do_subchapters );
    bool Leave( bool b_do_subchapters );
963
    bool EnterAndLeave( chapter_item_c *p_item, bool b_enter = true );
964
965
};

966
class chapter_edition_c : public chapter_item_c
967
968
{
public:
969
    chapter_edition_c()
970
    :b_ordered(false)
971
    {}
972
    
973
974
    void RefreshChapters( );
    mtime_t Duration() const;
975
    std::string GetMainName() const;
976
    chapter_item_c * FindTimecode( mtime_t i_timecode, const chapter_item_c * p_current );
977
978
    
    bool                        b_ordered;
979
980
};

981
class matroska_segment_c
Steve Lhomme's avatar
Steve Lhomme committed
982
983
{
public:
984
    matroska_segment_c( demux_sys_t & demuxer, EbmlStream & estream )
985
        :segment(NULL)
986
        ,es(estream)
987
        ,i_timescale(MKVD_TIMECODESCALE)
988
        ,i_duration(-1)
989
        ,i_start_time(0)
990
991
992
        ,i_cues_position(-1)
        ,i_chapters_position(-1)
        ,i_tags_position(-1)
Steve Lhomme's avatar
Steve Lhomme committed
993
        ,cluster(NULL)
994
995
        ,i_block_pos(0)
        ,i_cluster_pos(0)
996
        ,i_start_pos(0)
Steve Lhomme's avatar
Steve Lhomme committed
997
998
999
        ,p_segment_uid(NULL)
        ,p_prev_segment_uid(NULL)
        ,p_next_segment_uid(NULL)
1000
        ,b_cues(VLC_FALSE)
Steve Lhomme's avatar
Steve Lhomme committed
1001
        ,i_index(0)
1002
        ,i_index_max(1024)
Steve Lhomme's avatar
Steve Lhomme committed
1003
1004
1005
1006
1007
        ,psz_muxing_application(NULL)
        ,psz_writing_application(NULL)
        ,psz_segment_filename(NULL)
        ,psz_title(NULL)
        ,psz_date_utc(NULL)
1008
        ,i_default_edition(0)
1009
        ,sys(demuxer)
1010
        ,ep(NULL)
1011
        ,b_preloaded(false)
1012
    {
Steve Lhomme's avatar
Steve Lhomme committed
1013
        p_indexes = (mkv_index_t*)malloc( sizeof( mkv_index_t ) * i_index_max );
1014
    }
Steve Lhomme's avatar
Steve Lhomme committed
1015

1016
    virtual ~matroska_segment_c()
1017
    {
1018
1019
        for( size_t i_track = 0; i_track < tracks.size(); i_track++ )
        {
1020
            if( tracks[i_track]->fmt.psz_description )
1021
            {
1022
                free( tracks[i_track]->fmt.psz_description );
1023
            }
Steve Lhomme's avatar
Steve Lhomme committed
1024
/*            if( tracks[i_track]->psz_codec )
1025
            {
1026
                free( tracks[i_track]->psz_codec );
1027
            }
1028
            if( tracks[i_track]->fmt.psz_language )
1029
            {
1030
                free( tracks[i_track]->fmt.psz_language );
Steve Lhomme's avatar
Steve Lhomme committed
1031
            }*/
1032
            delete tracks[i_track];
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
        }
        
        if( psz_writing_application )
        {
            free( psz_writing_application );
        }
        if( psz_muxing_application )
        {
            free( psz_muxing_application );
        }
        if( psz_segment_filename )
        {
            free( psz_segment_filename );
        }
        if( psz_title )
        {
            free( psz_title );
        }
        if( psz_date_utc )
        {
            free( psz_date_utc );
        }
Steve Lhomme's avatar
Steve Lhomme committed
1055
1056
        if ( p_indexes )
            free( p_indexes );
1057

1058
        delete ep;
Steve Lhomme's avatar
Steve Lhomme committed
1059
1060
1061
        delete p_segment_uid;
        delete p_prev_segment_uid;
        delete p_next_segment_uid;
1062
1063
1064
1065
1066
1067
1068

        std::vector<chapter_edition_c*>::iterator index = stored_editions.begin();
        while ( index != stored_editions.end() )
        {
            delete (*index);
            index++;
        }
Steve Lhomme's avatar
Steve Lhomme committed
1069
1070
1071
1072
1073
1074
        std::vector<chapter_translation_c*>::iterator indext = translations.begin();
        while ( indext != translations.end() )
        {
            delete (*indext);
            indext++;
        }
1075
1076
    }

1077
    KaxSegment              *segment;
1078
    EbmlStream              & es;
Steve Lhomme's avatar
Steve Lhomme committed
1079
1080
1081
1082
1083

    /* time scale */
    uint64_t                i_timescale;

    /* duration of the segment */
1084
    mtime_t                 i_duration;
1085
    mtime_t                 i_start_time;
Steve Lhomme's avatar
Steve Lhomme committed
1086
1087

    /* all tracks */
1088
    std::vector<mkv_track_t*> tracks;
Steve Lhomme's avatar
Steve Lhomme committed
1089
1090
1091
1092
1093
1094
1095

    /* from seekhead */
    int64_t                 i_cues_position;
    int64_t                 i_chapters_position;
    int64_t                 i_tags_position;

    KaxCluster              *cluster;
1096
1097
    uint64                  i_block_pos;
    uint64                  i_cluster_pos;
1098
    int64_t                 i_start_pos;
Steve Lhomme's avatar
Steve Lhomme committed
1099
1100
1101
    KaxSegmentUID           *p_segment_uid;
    KaxPrevUID              *p_prev_segment_uid;
    KaxNextUID              *p_next_segment_uid;
Steve Lhomme's avatar
Steve Lhomme committed
1102
1103
1104
1105

    vlc_bool_t              b_cues;
    int                     i_index;
    int                     i_index_max;
Steve Lhomme's avatar
Steve Lhomme committed
1106
    mkv_index_t             *p_indexes;
Steve Lhomme's avatar
Steve Lhomme committed
1107
1108
1109
1110
1111
1112
1113
1114

    /* info */
    char                    *psz_muxing_application;
    char                    *psz_writing_application;
    char                    *psz_segment_filename;
    char                    *psz_title;
    char                    *psz_date_utc;

1115
1116
1117
    /* !!!!! GCC 3.3 bug on Darwin !!!!! */
    /* when you remove this variable the compiler issues an atomicity error */
    /* this variable only works when using std::vector<chapter_edition_c> */
1118
1119
    std::vector<chapter_edition_c*> stored_editions;
    int                             i_default_edition;
1120

Steve Lhomme's avatar
Steve Lhomme committed
1121
    std::vector<chapter_translation_c*> translations;
1122
    std::vector<KaxSegmentFamily>  families;
1123
    
1124
    demux_sys_t                    & sys;
1125
1126
    EbmlParser                     *ep;
    bool                           b_preloaded;
1127

1128
    bool Preload( );
1129
    bool PreloadFamily( const matroska_segment_c & segment );
Steve Lhomme's avatar
Steve Lhomme committed
1130
1131
1132
1133
    void ParseInfo( KaxInfo *info );
    void ParseChapters( KaxChapters *chapters );
    void ParseSeekHead( KaxSeekHead *seekhead );
    void ParseTracks( KaxTracks *tracks );
1134
    void ParseChapterAtom( int i_level, KaxChapterAtom *ca, chapter_item_c & chapters );
Steve Lhomme's avatar
Steve Lhomme committed
1135
    void ParseTrackEntry( KaxTrackEntry *m );
1136
    void ParseCluster( );
1137
    void IndexAppendCluster( KaxCluster *cluster );
1138
1139
1140
    void LoadCues( );
    void LoadTags( );
    void InformationCreate( );
1141
    void Seek( mtime_t i_date, mtime_t i_time_offset );
1142
    int BlockGet( KaxBlock * & pp_block, int64_t *pi_ref1, int64_t *pi_ref2, int64_t *pi_duration );
1143
    bool Select( mtime_t i_start_time );
1144
    void UnSelect( );
1145

1146
    static bool CompareSegmentUIDs( const matroska_segment_c * item_a, const matroska_segment_c * item_b );
1147
1148
};

1149
// class holding hard-linked segment together in the playback order
1150
class virtual_segment_c
1151
1152
{
public:
1153
    virtual_segment_c( matroska_segment_c *p_segment )
1154
1155
1156
        :p_editions(NULL)
        ,i_sys_title(0)
        ,i_current_segment(0)
1157
1158
        ,i_current_edition(-1)
        ,psz_current_chapter(NULL)
1159
1160
    {
        linked_segments.push_back( p_segment );
1161

Steve Lhomme's avatar
Steve Lhomme committed
1162
1163
1164
        AppendUID( p_segment->p_segment_uid );
        AppendUID( p_segment->p_prev_segment_uid );
        AppendUID( p_segment->p_next_segment_uid );
1165
    }
1166
1167

    void Sort();
1168
    size_t AddSegment( matroska_segment_c *p_segment );
1169
    void PreloadLinked( );
1170
    mtime_t Duration( ) const;
1171
    void LoadCues( );
Steve Lhomme's avatar
Steve Lhomme committed
1172
    void Seek( demux_t & demuxer, mtime_t i_date, mtime_t i_time_offset, chapter_item_c *psz_chapter );
1173

1174
    inline chapter_edition_c *Edition()
1175
    {
1176
1177
        if ( i_current_edition >= 0 && size_t(i_current_edition) < p_editions->size() )
            return (*p_editions)[i_current_edition];
1178
1179
        return NULL;
    }
1180

1181
    matroska_segment_c * Segment() const
1182
1183
1184
1185
1186
1187
    {
        if ( linked_segments.size() == 0 || i_current_segment >= linked_segments.size() )
            return NULL;
        return linked_segments[i_current_segment];
    }

1188
    inline chapter_item_c *CurrentChapter() {
1189
1190
1191
        return psz_current_chapter;
    }

1192
1193
1194
1195
1196
1197
1198
1199
1200
    bool SelectNext()
    {
        if ( i_current_segment < linked_segments.size()-1 )
        {
            i_current_segment++;
            return true;
        }
        return false;
    }
1201

1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
    bool FindUID( KaxSegmentUID & uid ) const
    {
        for ( size_t i=0; i<linked_uids.size(); i++ )
        {
            if ( linked_uids[i] == uid )
                return true;
        }
        return false;
    }

1212
    bool UpdateCurrentToChapter( demux_t & demux );
1213
    void PrepareChapters( );
1214

1215
1216
1217
1218
    chapter_item_c *BrowseCodecPrivate( unsigned int codec_id, 
                                        bool (*match)(const chapter_codec_cmds_c &data, const void *p_cookie, size_t i_cookie_size ), 
                                        const void *p_cookie, 
                                        size_t i_cookie_size );
1219
    chapter_item_c *FindChapter( int64_t i_find_uid );
1220
1221
1222
1223

    std::vector<chapter_edition_c*>  *p_editions;
    int                              i_sys_title;

1224
protected:
1225
    std::vector<matroska_segment_c*> linked_segments;
1226
    std::vector<KaxSegmentUID>       linked_uids;
1227
1228
    size_t                           i_current_segment;

1229
    int                              i_current_edition;
Steve Lhomme's avatar
Steve Lhomme committed
1230
    chapter_item_c                   *psz_current_chapter;
1231

Steve Lhomme's avatar
Steve Lhomme committed
1232
    void                             AppendUID( const EbmlBinary * UID );
1233
1234
};

1235
class matroska_stream_c
1236
1237
{
public:
1238
    matroska_stream_c( demux_sys_t & demuxer )
1239
1240
1241
        :p_in(NULL)
        ,p_es(NULL)
        ,sys(demuxer)
1242
1243