mkv.cpp 84.5 KB
Newer Older
1
2
3
4
/*****************************************************************************
 * mkv.cpp : matroska demuxer
 *****************************************************************************
 * Copyright (C) 2001 VideoLAN
5
 * $Id: mkv.cpp,v 1.28 2003/10/11 21:08:40 hartman Exp $
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
 *
 * Authors: Laurent Aimar <fenrir@via.ecp.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>

31
32
33
34
#ifdef HAVE_TIME_H
#   include <time.h>                                               /* time() */
#endif

35
36
37
#include <vlc/input.h>

#include <codecs.h>                        /* BITMAPINFOHEADER, WAVEFORMATEX */
38
#include "iso_lang.h"
39
40
41
42
43

#include <iostream>
#include <cassert>
#include <typeinfo>

44
45
46
#ifdef HAVE_WCHAR_H
#   include <wchar.h>
#endif
Laurent Aimar's avatar
Laurent Aimar committed
47

48
49
50
51
52
53
54
55
56
/* libebml and matroska */
#include "ebml/EbmlHead.h"
#include "ebml/EbmlSubHead.h"
#include "ebml/EbmlStream.h"
#include "ebml/EbmlContexts.h"
#include "ebml/EbmlVersion.h"
#include "ebml/EbmlVoid.h"

#include "matroska/FileKax.h"
57
58
59
#ifdef HAVE_MATROSKA_KAXATTACHMENTS_H
#include "matroska/KaxAttachments.h"
#else
60
#include "matroska/KaxAttachements.h"
61
#endif
62
63
64
65
66
67
68
69
70
71
72
73
74
#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"
75
76
#include "matroska/KaxTags.h"
#include "matroska/KaxTagMulti.h"
77
78
79
#include "matroska/KaxTracks.h"
#include "matroska/KaxTrackAudio.h"
#include "matroska/KaxTrackVideo.h"
80
#include "matroska/KaxTrackEntryData.h"
81
82
83
84
85
86
87
88
89

#include "ebml/StdIOCallback.h"

using namespace LIBMATROSKA_NAMESPACE;
using namespace std;

/*****************************************************************************
 * Module descriptor
 *****************************************************************************/
Laurent Aimar's avatar
Laurent Aimar committed
90
91
92
static int  Open ( vlc_object_t * );
static void Close( vlc_object_t * );

93
vlc_module_begin();
94
    add_category_hint( N_("mkv-demuxer"), NULL, VLC_TRUE );
95
96
97
98
        add_bool( "mkv-seek-percent", 1, NULL,
                  N_("Seek based on percent not time"),
                  N_("Seek based on percent not time"), VLC_TRUE );

99
100
    set_description( _("mka/mkv stream demuxer" ) );
    set_capability( "demux", 50 );
Laurent Aimar's avatar
Laurent Aimar committed
101
    set_callbacks( Open, Close );
102
103
104
105
    add_shortcut( "mka" );
    add_shortcut( "mkv" );
vlc_module_end();

Laurent Aimar's avatar
Laurent Aimar committed
106
107
108
109
110
111
/*****************************************************************************
 * Local prototypes
 *****************************************************************************/
static int  Demux   ( input_thread_t * );
static void Seek    ( input_thread_t *, mtime_t i_date, int i_percent );

112
113
114
115
116
117
118

/*****************************************************************************
 * Stream managment
 *****************************************************************************/
class vlc_stream_io_callback: public IOCallback
{
  private:
Laurent Aimar's avatar
Laurent Aimar committed
119
    stream_t       *s;
120
    vlc_bool_t     mb_eof;
121
122

  public:
Laurent Aimar's avatar
Laurent Aimar committed
123
    vlc_stream_io_callback( stream_t * );
124
125
126
127
128
129
130
131

    virtual uint32_t 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_t getFilePointer  ( void );
    virtual void     close           ( void );
};

132
133
134
135
/*****************************************************************************
 * Ebml Stream parser
 *****************************************************************************/
class EbmlParser
136
{
137
138
139
  public:
    EbmlParser( EbmlStream *es, EbmlElement *el_start );
    ~EbmlParser( void );
140

141
142
143
144
    void Up( void );
    void Down( void );
    EbmlElement *Get( void );
    void        Keep( void );
145

146
    int GetLevel( void );
147

148
149
150
151
  private:
    EbmlStream  *m_es;
    int         mi_level;
    EbmlElement *m_el[6];
152

153
    EbmlElement *m_got;
154

155
156
157
    int         mi_user_level;
    vlc_bool_t  mb_keep;
};
158
159


160
161
162
163
164
165
166
/*****************************************************************************
 * 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] );
167
168
}

169
170
171
172
/*****************************************************************************
 * definitions of structures and functions used by this plugins
 *****************************************************************************/
typedef struct
173
{
174
175
    int         i_cat;
    vlc_bool_t  b_default;
176
    vlc_bool_t  b_enabled;
177
    int         i_number;
178

179
180
    int         i_extra_data;
    uint8_t     *p_extra_data;
181

182
    char         *psz_language;
183

184
185
    char         *psz_codec;
    vlc_fourcc_t i_codec;
186

187
    uint64_t     i_default_duration;
188
    float        f_timecodescale;
189
190
191
192
193
194
    /* video */
    int         i_width;
    int         i_height;
    int         i_display_width;
    int         i_display_height;
    float       f_fps;
195
196


197
198
199
200
    /* audio */
    int         i_channels;
    int         i_samplerate;
    int         i_bitspersample;
201

202
    es_descriptor_t *p_es;
203
204
205



206
207
208
209
    vlc_bool_t      b_inited;
    /* data to be send first */
    int             i_data_init;
    uint8_t         *p_data_init;
210

211
212
    /* hack : it's for seek */
    vlc_bool_t      b_search_keyframe;
213
214
215
216
217
218
219
220

    /* informative */
    char         *psz_name;
    char         *psz_codec_name;
    char         *psz_codec_settings;
    char         *psz_codec_info_url;
    char         *psz_codec_download_url;

221
} mkv_track_t;
222

223
typedef struct
224
{
225
226
    int     i_track;
    int     i_block_number;
227

228
229
    int64_t i_position;
    int64_t i_time;
230

231
232
    vlc_bool_t b_key;
} mkv_index_t;
233

234
struct demux_sys_t
235
{
236
237
238
    vlc_stream_io_callback  *in;
    EbmlStream              *es;
    EbmlParser              *ep;
239

240
241
    /* time scale */
    uint64_t                i_timescale;
242

243
244
    /* duration of the segment */
    float                   f_duration;
245

246
247
248
    /* all tracks */
    int                     i_track;
    mkv_track_t             *track;
249

250
251
252
253
    /* from seekhead */
    int64_t                 i_cues_position;
    int64_t                 i_chapters_position;
    int64_t                 i_tags_position;
254

255
256
257
    /* current data */
    KaxSegment              *segment;
    KaxCluster              *cluster;
258

259
    mtime_t                 i_pts;
260

261
262
263
264
    vlc_bool_t              b_cues;
    int                     i_index;
    int                     i_index_max;
    mkv_index_t             *index;
265

266
267
268
269
270
271
    /* info */
    char                    *psz_muxing_application;
    char                    *psz_writing_application;
    char                    *psz_segment_filename;
    char                    *psz_title;
    char                    *psz_date_utc;
272
273
};

274
275
276
277
278
279
280
#define MKVD_TIMECODESCALE 1000000

static void IndexAppendCluster  ( input_thread_t *p_input, KaxCluster *cluster );
static char *UTF8ToStr          ( const UTFstring &u );
static void LoadCues            ( input_thread_t *);
static void InformationsCreate  ( input_thread_t *p_input );

281
282
static char *LanguageGetName    ( const char *psz_code );

283
/*****************************************************************************
Laurent Aimar's avatar
Laurent Aimar committed
284
 * Open: initializes matroska demux structures
285
 *****************************************************************************/
Laurent Aimar's avatar
Laurent Aimar committed
286
static int Open( vlc_object_t * p_this )
287
{
288
289
290
    input_thread_t *p_input = (input_thread_t *)p_this;
    demux_sys_t    *p_sys;
    uint8_t        *p_peek;
291

292
293
294
    int             i_track;
    vlc_bool_t      b_audio_selected;
    int             i_spu_channel, i_audio_channel;
295

296
297
298
299
    EbmlElement     *el = NULL, *el1 = NULL, *el2 = NULL, *el3 = NULL, *el4 = NULL;

    /* Set the demux function */
    p_input->pf_demux = Demux;
300
    p_input->pf_demux_control = demux_vaControlDefault;
301

302
303
    /* peek the begining */
    if( input_Peek( p_input, &p_peek, 4 ) < 4 )
304
305
306
307
308
309
    {
        msg_Warn( p_input, "cannot peek" );
        return VLC_EGENERIC;
    }

    /* is a valid file */
Laurent Aimar's avatar
Laurent Aimar committed
310
311
    if( p_peek[0] != 0x1a || p_peek[1] != 0x45 ||
        p_peek[2] != 0xdf || p_peek[3] != 0xa3 )
312
    {
313
314
315
        msg_Warn( p_input, "matroska module discarded "
                           "(invalid header 0x%.2x%.2x%.2x%.2x)",
                           p_peek[0], p_peek[1], p_peek[2], p_peek[3] );
316
317
318
        return VLC_EGENERIC;
    }

Laurent Aimar's avatar
Laurent Aimar committed
319
    p_input->p_demux_data = p_sys = (demux_sys_t*)malloc(sizeof( demux_sys_t ));
320
321
    memset( p_sys, 0, sizeof( demux_sys_t ) );

322
    p_sys->in = new vlc_stream_io_callback( p_input->s );
323
324
    p_sys->es = new EbmlStream( *p_sys->in );
    p_sys->f_duration   = -1;
325
    p_sys->i_timescale     = MKVD_TIMECODESCALE;
326
327
    p_sys->i_track      = 0;
    p_sys->track        = (mkv_track_t*)malloc( sizeof( mkv_track_t ) );
328
329
330
    p_sys->i_pts   = 0;
    p_sys->i_cues_position = -1;
    p_sys->i_chapters_position = -1;
331
    p_sys->i_tags_position = -1;
332

333
    p_sys->b_cues       = VLC_FALSE;
334
335
    p_sys->i_index      = 0;
    p_sys->i_index_max  = 1024;
Laurent Aimar's avatar
Laurent Aimar committed
336
337
    p_sys->index        = (mkv_index_t*)malloc( sizeof( mkv_index_t ) *
                                                p_sys->i_index_max );
338

339
340
341
342
343
344
    p_sys->psz_muxing_application = NULL;
    p_sys->psz_writing_application = NULL;
    p_sys->psz_segment_filename = NULL;
    p_sys->psz_title = NULL;
    p_sys->psz_date_utc = NULL;;

345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
    if( p_sys->es == NULL )
    {
        msg_Err( p_input, "failed to create EbmlStream" );
        delete p_sys->in;
        free( p_sys );
        return VLC_EGENERIC;
    }
    /* Find the EbmlHead element */
    el = p_sys->es->FindNextID(EbmlHead::ClassInfos, 0xFFFFFFFFL);
    if( el == NULL )
    {
        msg_Err( p_input, "cannot find EbmlHead" );
        goto error;
    }
    msg_Dbg( p_input, "EbmlHead" );
    /* skip it */
    el->SkipData( *p_sys->es, el->Generic().Context );
    delete el;

    /* Find a segment */
    el = p_sys->es->FindNextID( KaxSegment::ClassInfos, 0xFFFFFFFFL);
    if( el == NULL )
    {
        msg_Err( p_input, "cannot find KaxSegment" );
        goto error;
    }
    msg_Dbg( p_input, "+ Segment" );
    p_sys->segment = (KaxSegment*)el;
    p_sys->cluster = NULL;

    p_sys->ep = new EbmlParser( p_sys->es, el );

    while( ( el1 = p_sys->ep->Get() ) != NULL )
    {
        if( EbmlId( *el1 ) == KaxInfo::ClassInfos.GlobalId )
        {
            msg_Dbg( p_input, "|   + Informations" );

            p_sys->ep->Down();
            while( ( el2 = p_sys->ep->Get() ) != NULL )
            {
                if( EbmlId( *el2 ) == KaxTimecodeScale::ClassInfos.GlobalId )
                {
                    KaxTimecodeScale &tcs = *(KaxTimecodeScale*)el2;

                    tcs.ReadData( p_sys->es->I_O() );
391
                    p_sys->i_timescale = uint64(tcs);
392

gbazin's avatar
   
gbazin committed
393
394
                    msg_Dbg( p_input, "|   |   + TimecodeScale="I64Fd,
                             p_sys->i_timescale );
395
396
397
398
399
400
401
402
                }
                else if( EbmlId( *el2 ) == KaxDuration::ClassInfos.GlobalId )
                {
                    KaxDuration &dur = *(KaxDuration*)el2;

                    dur.ReadData( p_sys->es->I_O() );
                    p_sys->f_duration = float(dur);

Laurent Aimar's avatar
Laurent Aimar committed
403
404
                    msg_Dbg( p_input, "|   |   + Duration=%f",
                             p_sys->f_duration );
405
                }
406
                else if( EbmlId( *el2 ) == KaxMuxingApp::ClassInfos.GlobalId )
407
                {
408
409
410
411
412
413
                    KaxMuxingApp &mapp = *(KaxMuxingApp*)el2;

                    mapp.ReadData( p_sys->es->I_O() );

                    p_sys->psz_muxing_application = UTF8ToStr( UTFstring( mapp ) );

Laurent Aimar's avatar
Laurent Aimar committed
414
415
                    msg_Dbg( p_input, "|   |   + Muxing Application=%s",
                             p_sys->psz_muxing_application );
416
                }
417
418
419
420
421
422
423
424
                else if( EbmlId( *el2 ) == KaxWritingApp::ClassInfos.GlobalId )
                {
                    KaxWritingApp &wapp = *(KaxWritingApp*)el2;

                    wapp.ReadData( p_sys->es->I_O() );

                    p_sys->psz_writing_application = UTF8ToStr( UTFstring( wapp ) );

Laurent Aimar's avatar
Laurent Aimar committed
425
426
                    msg_Dbg( p_input, "|   |   + Wrinting Application=%s",
                             p_sys->psz_writing_application );
427
428
429
430
431
432
433
434
435
                }
                else if( EbmlId( *el2 ) == KaxSegmentFilename::ClassInfos.GlobalId )
                {
                    KaxSegmentFilename &sfn = *(KaxSegmentFilename*)el2;

                    sfn.ReadData( p_sys->es->I_O() );

                    p_sys->psz_segment_filename = UTF8ToStr( UTFstring( sfn ) );

Laurent Aimar's avatar
Laurent Aimar committed
436
437
                    msg_Dbg( p_input, "|   |   + Segment Filename=%s",
                             p_sys->psz_segment_filename );
438
439
440
441
442
443
444
445
446
447
448
                }
                else if( EbmlId( *el2 ) == KaxTitle::ClassInfos.GlobalId )
                {
                    KaxTitle &title = *(KaxTitle*)el2;

                    title.ReadData( p_sys->es->I_O() );

                    p_sys->psz_title = UTF8ToStr( UTFstring( title ) );

                    msg_Dbg( p_input, "|   |   + Title=%s", p_sys->psz_title );
                }
449
#ifdef HAVE_GMTIME_R
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
                else if( EbmlId( *el2 ) == KaxDateUTC::ClassInfos.GlobalId )
                {
                    KaxDateUTC &date = *(KaxDateUTC*)el2;
                    time_t i_date;
                    struct tm tmres;
                    char   buffer[256];

                    date.ReadData( p_sys->es->I_O() );

                    i_date = date.GetEpochDate();
                    memset( buffer, 0, 256 );
                    if( gmtime_r( &i_date, &tmres ) &&
                        asctime_r( &tmres, buffer ) )
                    {
                        buffer[strlen( buffer)-1]= '\0';
                        p_sys->psz_date_utc = strdup( buffer );
                        msg_Dbg( p_input, "|   |   + Date=%s", p_sys->psz_date_utc );
                    }
                }
#endif
                else
                {
Laurent Aimar's avatar
Laurent Aimar committed
472
                    msg_Dbg( p_input, "|   |   + Unknown (%s)", typeid(*el2).name() );
473
474
                }
            }
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
            p_sys->ep->Up();
        }
        else if( EbmlId( *el1 ) == KaxTracks::ClassInfos.GlobalId )
        {
            msg_Dbg( p_input, "|   + Tracks" );

            p_sys->ep->Down();
            while( ( el2 = p_sys->ep->Get() ) != NULL )
            {
                if( EbmlId( *el2 ) == KaxTrackEntry::ClassInfos.GlobalId )
                {
                    msg_Dbg( p_input, "|   |   + Track Entry" );

                    p_sys->i_track++;
                    p_sys->track = (mkv_track_t*)realloc( p_sys->track, sizeof( mkv_track_t ) * (p_sys->i_track + 1 ) );
#define tk  p_sys->track[p_sys->i_track - 1]
                    memset( &tk, 0, sizeof( mkv_track_t ) );
                    tk.i_cat = UNKNOWN_ES;
493
494
                    tk.b_default = VLC_TRUE;
                    tk.b_enabled = VLC_TRUE;
495
496
497
498
499
500
501
                    tk.i_number = p_sys->i_track - 1;
                    tk.i_extra_data = 0;
                    tk.p_extra_data = NULL;
                    tk.i_codec = 0;
                    tk.psz_codec = NULL;
                    tk.psz_language = NULL;
                    tk.i_default_duration = 0;
502
                    tk.f_timecodescale = 1.0;
503
504
505
506
507

                    tk.b_inited = VLC_FALSE;
                    tk.i_data_init = 0;
                    tk.p_data_init = NULL;

508
509
510
511
512
513
                    tk.psz_name = NULL;
                    tk.psz_codec_name = NULL;
                    tk.psz_codec_settings = NULL;
                    tk.psz_codec_info_url = NULL;
                    tk.psz_codec_download_url = NULL;

514
515
516
517
518
519
520
521
522
523
                    p_sys->ep->Down();

                    while( ( el3 = p_sys->ep->Get() ) != NULL )
                    {
                        if( EbmlId( *el3 ) == KaxTrackNumber::ClassInfos.GlobalId )
                        {
                            KaxTrackNumber &tnum = *(KaxTrackNumber*)el3;
                            tnum.ReadData( p_sys->es->I_O() );

                            tk.i_number = uint32( tnum );
Laurent Aimar's avatar
Laurent Aimar committed
524
525
                            msg_Dbg( p_input, "|   |   |   + Track Number=%u",
                                     uint32( tnum ) );
526
527
528
529
530
531
                        }
                        else  if( EbmlId( *el3 ) == KaxTrackUID::ClassInfos.GlobalId )
                        {
                            KaxTrackUID &tuid = *(KaxTrackUID*)el3;
                            tuid.ReadData( p_sys->es->I_O() );

Laurent Aimar's avatar
Laurent Aimar committed
532
533
                            msg_Dbg( p_input, "|   |   |   + Track UID=%u",
                                     uint32( tuid ) );
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
                        }
                        else  if( EbmlId( *el3 ) == KaxTrackType::ClassInfos.GlobalId )
                        {
                            char *psz_type;
                            KaxTrackType &ttype = *(KaxTrackType*)el3;
                            ttype.ReadData( p_sys->es->I_O() );
                            switch( uint8(ttype) )
                            {
                                case track_audio:
                                    psz_type = "audio";
                                    tk.i_cat = AUDIO_ES;
                                    break;
                                case track_video:
                                    psz_type = "video";
                                    tk.i_cat = VIDEO_ES;
                                    break;
                                case track_subtitle:
                                    psz_type = "subtitle";
                                    tk.i_cat = SPU_ES;
                                    break;
                                default:
                                    psz_type = "unknown";
                                    tk.i_cat = UNKNOWN_ES;
                                    break;
                            }

560
561
                            msg_Dbg( p_input, "|   |   |   + Track Type=%s",
                                     psz_type );
562
                        }
563
                        else  if( EbmlId( *el3 ) == KaxTrackFlagEnabled::ClassInfos.GlobalId )
564
                        {
565
566
                            KaxTrackFlagEnabled &fenb = *(KaxTrackFlagEnabled*)el3;
                            fenb.ReadData( p_sys->es->I_O() );
567

568
                            tk.b_enabled = uint32( fenb );
569
570
                            msg_Dbg( p_input, "|   |   |   + Track Enabled=%u",
                                     uint32( fenb )  );
571
572
573
574
575
                        }
                        else  if( EbmlId( *el3 ) == KaxTrackFlagDefault::ClassInfos.GlobalId )
                        {
                            KaxTrackFlagDefault &fdef = *(KaxTrackFlagDefault*)el3;
                            fdef.ReadData( p_sys->es->I_O() );
576

577
                            tk.b_default = uint32( fdef );
578
579
                            msg_Dbg( p_input, "|   |   |   + Track Default=%u",
                                     uint32( fdef )  );
580
581
582
583
584
                        }
                        else  if( EbmlId( *el3 ) == KaxTrackFlagLacing::ClassInfos.GlobalId )
                        {
                            KaxTrackFlagLacing &lac = *(KaxTrackFlagLacing*)el3;
                            lac.ReadData( p_sys->es->I_O() );
585

586
587
                            msg_Dbg( p_input, "|   |   |   + Track Lacing=%d",
                                     uint32( lac ) );
588
589
590
591
592
                        }
                        else  if( EbmlId( *el3 ) == KaxTrackMinCache::ClassInfos.GlobalId )
                        {
                            KaxTrackMinCache &cmin = *(KaxTrackMinCache*)el3;
                            cmin.ReadData( p_sys->es->I_O() );
593

594
595
                            msg_Dbg( p_input, "|   |   |   + Track MinCache=%d",
                                     uint32( cmin ) );
596
597
598
599
600
                        }
                        else  if( EbmlId( *el3 ) == KaxTrackMaxCache::ClassInfos.GlobalId )
                        {
                            KaxTrackMaxCache &cmax = *(KaxTrackMaxCache*)el3;
                            cmax.ReadData( p_sys->es->I_O() );
601

602
603
                            msg_Dbg( p_input, "|   |   |   + Track MaxCache=%d",
                                     uint32( cmax ) );
604
605
606
607
608
609
610
                        }
                        else  if( EbmlId( *el3 ) == KaxTrackDefaultDuration::ClassInfos.GlobalId )
                        {
                            KaxTrackDefaultDuration &defd = *(KaxTrackDefaultDuration*)el3;
                            defd.ReadData( p_sys->es->I_O() );

                            tk.i_default_duration = uint64(defd);
gbazin's avatar
   
gbazin committed
611
                            msg_Dbg( p_input, "|   |   |   + Track Default Duration="I64Fd, uint64(defd) );
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
                        }
                        else  if( EbmlId( *el3 ) == KaxTrackTimecodeScale::ClassInfos.GlobalId )
                        {
                            KaxTrackTimecodeScale &ttcs = *(KaxTrackTimecodeScale*)el3;
                            ttcs.ReadData( p_sys->es->I_O() );

                            tk.f_timecodescale = float( ttcs );
                            msg_Dbg( p_input, "|   |   |   + Track TimeCodeScale=%f", tk.f_timecodescale );
                        }
                        else if( EbmlId( *el3 ) == KaxTrackName::ClassInfos.GlobalId )
                        {
                            KaxTrackName &tname = *(KaxTrackName*)el3;
                            tname.ReadData( p_sys->es->I_O() );

                            tk.psz_name = UTF8ToStr( UTFstring( tname ) );
627
628
                            msg_Dbg( p_input, "|   |   |   + Track Name=%s",
                                     tk.psz_name );
629
630
631
632
633
634
                        }
                        else  if( EbmlId( *el3 ) == KaxTrackLanguage::ClassInfos.GlobalId )
                        {
                            KaxTrackLanguage &lang = *(KaxTrackLanguage*)el3;
                            lang.ReadData( p_sys->es->I_O() );

635
636
637
638
639
                            tk.psz_language =
                                LanguageGetName( string( lang ).c_str() );
                            msg_Dbg( p_input,
                                     "|   |   |   + Track Language=`%s'(%s) ",
                                     tk.psz_language, string( lang ).c_str() );
640
641
642
643
644
645
646
                        }
                        else  if( EbmlId( *el3 ) == KaxCodecID::ClassInfos.GlobalId )
                        {
                            KaxCodecID &codecid = *(KaxCodecID*)el3;
                            codecid.ReadData( p_sys->es->I_O() );

                            tk.psz_codec = strdup( string( codecid ).c_str() );
647
648
                            msg_Dbg( p_input, "|   |   |   + Track CodecId=%s",
                                     string( codecid ).c_str() );
649
650
651
652
653
654
655
656
657
658
659
                        }
                        else  if( EbmlId( *el3 ) == KaxCodecPrivate::ClassInfos.GlobalId )
                        {
                            KaxCodecPrivate &cpriv = *(KaxCodecPrivate*)el3;
                            cpriv.ReadData( p_sys->es->I_O() );

                            tk.i_extra_data = cpriv.GetSize();
                            if( tk.i_extra_data > 0 )
                            {
                                tk.p_extra_data = (uint8_t*)malloc( tk.i_extra_data );
                                memcpy( tk.p_extra_data, cpriv.GetBuffer(), tk.i_extra_data );
660
                            }
gbazin's avatar
   
gbazin committed
661
                            msg_Dbg( p_input, "|   |   |   + Track CodecPrivate size="I64Fd, cpriv.GetSize() );
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
                        }
                        else if( EbmlId( *el3 ) == KaxCodecName::ClassInfos.GlobalId )
                        {
                            KaxCodecName &cname = *(KaxCodecName*)el3;
                            cname.ReadData( p_sys->es->I_O() );

                            tk.psz_codec_name = UTF8ToStr( UTFstring( cname ) );
                            msg_Dbg( p_input, "|   |   |   + Track Codec Name=%s", tk.psz_codec_name );
                        }
                        else if( EbmlId( *el3 ) == KaxCodecSettings::ClassInfos.GlobalId )
                        {
                            KaxCodecSettings &cset = *(KaxCodecSettings*)el3;
                            cset.ReadData( p_sys->es->I_O() );

                            tk.psz_codec_settings = UTF8ToStr( UTFstring( cset ) );
                            msg_Dbg( p_input, "|   |   |   + Track Codec Settings=%s", tk.psz_codec_settings );
                        }
                        else if( EbmlId( *el3 ) == KaxCodecInfoURL::ClassInfos.GlobalId )
                        {
                            KaxCodecInfoURL &ciurl = *(KaxCodecInfoURL*)el3;
                            ciurl.ReadData( p_sys->es->I_O() );

                            tk.psz_codec_info_url = strdup( string( ciurl ).c_str() );
                            msg_Dbg( p_input, "|   |   |   + Track Codec Info URL=%s", tk.psz_codec_info_url );
                        }
                        else if( EbmlId( *el3 ) == KaxCodecDownloadURL::ClassInfos.GlobalId )
                        {
                            KaxCodecDownloadURL &cdurl = *(KaxCodecDownloadURL*)el3;
                            cdurl.ReadData( p_sys->es->I_O() );

                            tk.psz_codec_download_url = strdup( string( cdurl ).c_str() );
                            msg_Dbg( p_input, "|   |   |   + Track Codec Info URL=%s", tk.psz_codec_download_url );
                        }
                        else if( EbmlId( *el3 ) == KaxCodecDecodeAll::ClassInfos.GlobalId )
                        {
                            KaxCodecDecodeAll &cdall = *(KaxCodecDecodeAll*)el3;
                            cdall.ReadData( p_sys->es->I_O() );

                            msg_Dbg( p_input, "|   |   |   + Track Codec Decode All=%u <== UNUSED", uint8( cdall ) );
                        }
                        else if( EbmlId( *el3 ) == KaxTrackOverlay::ClassInfos.GlobalId )
                        {
                            KaxTrackOverlay &tovr = *(KaxTrackOverlay*)el3;
                            tovr.ReadData( p_sys->es->I_O() );

                            msg_Dbg( p_input, "|   |   |   + Track Overlay=%u <== UNUSED", uint32( tovr ) );
708
709
710
711
712
713
714
715
716
717
718
719
720
721
                        }
                        else  if( EbmlId( *el3 ) == KaxTrackVideo::ClassInfos.GlobalId )
                        {
                            msg_Dbg( p_input, "|   |   |   + Track Video" );
                            tk.i_width  = 0;
                            tk.i_height = 0;
                            tk.i_display_width  = 0;
                            tk.i_display_height = 0;
                            tk.f_fps = 0.0;

                            p_sys->ep->Down();

                            while( ( el4 = p_sys->ep->Get() ) != NULL )
                            {
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
                                if( EbmlId( *el4 ) == KaxVideoFlagInterlaced::ClassInfos.GlobalId )
                                {
                                    KaxVideoFlagInterlaced &fint = *(KaxVideoFlagInterlaced*)el4;
                                    fint.ReadData( p_sys->es->I_O() );

                                    msg_Dbg( p_input, "|   |   |   |   + Track Video Interlaced=%u", uint8( fint ) );
                                }
                                else if( EbmlId( *el4 ) == KaxVideoStereoMode::ClassInfos.GlobalId )
                                {
                                    KaxVideoStereoMode &stereo = *(KaxVideoStereoMode*)el4;
                                    stereo.ReadData( p_sys->es->I_O() );

                                    msg_Dbg( p_input, "|   |   |   |   + Track Video Stereo Mode=%u", uint8( stereo ) );
                                }
                                else if( EbmlId( *el4 ) == KaxVideoPixelWidth::ClassInfos.GlobalId )
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
                                {
                                    KaxVideoPixelWidth &vwidth = *(KaxVideoPixelWidth*)el4;
                                    vwidth.ReadData( p_sys->es->I_O() );

                                    tk.i_width = uint16( vwidth );
                                    msg_Dbg( p_input, "|   |   |   |   + width=%d", uint16( vwidth ) );
                                }
                                else if( EbmlId( *el4 ) == KaxVideoPixelHeight::ClassInfos.GlobalId )
                                {
                                    KaxVideoPixelWidth &vheight = *(KaxVideoPixelWidth*)el4;
                                    vheight.ReadData( p_sys->es->I_O() );

                                    tk.i_height = uint16( vheight );
                                    msg_Dbg( p_input, "|   |   |   |   + height=%d", uint16( vheight ) );
                                }
                                else if( EbmlId( *el4 ) == KaxVideoDisplayWidth::ClassInfos.GlobalId )
                                {
                                    KaxVideoDisplayWidth &vwidth = *(KaxVideoDisplayWidth*)el4;
                                    vwidth.ReadData( p_sys->es->I_O() );

                                    tk.i_display_width = uint16( vwidth );
                                    msg_Dbg( p_input, "|   |   |   |   + display width=%d", uint16( vwidth ) );
                                }
                                else if( EbmlId( *el4 ) == KaxVideoDisplayHeight::ClassInfos.GlobalId )
                                {
                                    KaxVideoDisplayWidth &vheight = *(KaxVideoDisplayWidth*)el4;
                                    vheight.ReadData( p_sys->es->I_O() );

                                    tk.i_display_height = uint16( vheight );
                                    msg_Dbg( p_input, "|   |   |   |   + display height=%d", uint16( vheight ) );
                                }
                                else if( EbmlId( *el4 ) == KaxVideoFrameRate::ClassInfos.GlobalId )
                                {
                                    KaxVideoFrameRate &vfps = *(KaxVideoFrameRate*)el4;
                                    vfps.ReadData( p_sys->es->I_O() );

                                    tk.f_fps = float( vfps );
                                    msg_Dbg( p_input, "   |   |   |   + fps=%f", float( vfps ) );
                                }
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
                                else if( EbmlId( *el4 ) == KaxVideoDisplayUnit::ClassInfos.GlobalId )
                                {
                                     KaxVideoDisplayUnit &vdmode = *(KaxVideoDisplayUnit*)el4;
                                    vdmode.ReadData( p_sys->es->I_O() );

                                    msg_Dbg( p_input, "|   |   |   |   + Track Video Display Unit=%s",
                                             uint8( vdmode ) == 0 ? "pixels" : ( uint8( vdmode ) == 1 ? "centimeters": "inches" ) );
                                }
                                else if( EbmlId( *el4 ) == KaxVideoAspectRatio::ClassInfos.GlobalId )
                                {
                                    KaxVideoAspectRatio &ratio = *(KaxVideoAspectRatio*)el4;
                                    ratio.ReadData( p_sys->es->I_O() );

                                    msg_Dbg( p_input, "   |   |   |   + Track Video Aspect Ratio Type=%u", uint8( ratio ) );
                                }
                                else if( EbmlId( *el4 ) == KaxVideoGamma::ClassInfos.GlobalId )
                                {
                                    KaxVideoGamma &gamma = *(KaxVideoGamma*)el4;
                                    gamma.ReadData( p_sys->es->I_O() );

                                    msg_Dbg( p_input, "   |   |   |   + fps=%f", float( gamma ) );
                                }
798
799
                                else
                                {
Laurent Aimar's avatar
Laurent Aimar committed
800
                                    msg_Dbg( p_input, "|   |   |   |   + Unknown (%s)", typeid(*el4).name() );
801
802
803
804
                                }
                            }
                            p_sys->ep->Up();
                        }
805
                        else  if( EbmlId( *el3 ) == KaxTrackAudio::ClassInfos.GlobalId )
806
                        {
807
808
809
810
                            msg_Dbg( p_input, "|   |   |   + Track Audio" );
                            tk.i_channels = 0;
                            tk.i_samplerate = 0;
                            tk.i_bitspersample = 0;
811

812
                            p_sys->ep->Down();
813

814
                            while( ( el4 = p_sys->ep->Get() ) != NULL )
815
                            {
816
817
818
819
                                if( EbmlId( *el4 ) == KaxAudioSamplingFreq::ClassInfos.GlobalId )
                                {
                                    KaxAudioSamplingFreq &afreq = *(KaxAudioSamplingFreq*)el4;
                                    afreq.ReadData( p_sys->es->I_O() );
820

821
822
823
824
825
826
827
                                    tk.i_samplerate = (int)float( afreq );
                                    msg_Dbg( p_input, "|   |   |   |   + afreq=%d", tk.i_samplerate );
                                }
                                else if( EbmlId( *el4 ) == KaxAudioChannels::ClassInfos.GlobalId )
                                {
                                    KaxAudioChannels &achan = *(KaxAudioChannels*)el4;
                                    achan.ReadData( p_sys->es->I_O() );
828

829
830
831
832
833
834
835
                                    tk.i_channels = uint8( achan );
                                    msg_Dbg( p_input, "|   |   |   |   + achan=%u", uint8( achan ) );
                                }
                                else if( EbmlId( *el4 ) == KaxAudioBitDepth::ClassInfos.GlobalId )
                                {
                                    KaxAudioBitDepth &abits = *(KaxAudioBitDepth*)el4;
                                    abits.ReadData( p_sys->es->I_O() );
836

837
838
839
840
841
842
843
844
845
                                    tk.i_bitspersample = uint8( abits );
                                    msg_Dbg( p_input, "|   |   |   |   + abits=%u", uint8( abits ) );
                                }
                                else
                                {
                                    msg_Dbg( p_input, "|   |   |   |   + Unknown (%s)", typeid(*el4).name() );
                                }
                            }
                            p_sys->ep->Up();
846
847
848
                        }
                        else
                        {
Laurent Aimar's avatar
Laurent Aimar committed
849
850
                            msg_Dbg( p_input, "|   |   |   + Unknown (%s)",
                                     typeid(*el3).name() );
851
852
853
854
855
856
                        }
                    }
                    p_sys->ep->Up();
                }
                else
                {
Laurent Aimar's avatar
Laurent Aimar committed
857
858
                    msg_Dbg( p_input, "|   |   + Unknown (%s)",
                             typeid(*el2).name() );
859
860
861
862
863
864
865
866
                }
#undef tk
            }
            p_sys->ep->Up();
        }
        else if( EbmlId( *el1 ) == KaxSeekHead::ClassInfos.GlobalId )
        {
            msg_Dbg( p_input, "|   + Seek head" );
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
            p_sys->ep->Down();
            while( ( el = p_sys->ep->Get() ) != NULL )
            {
                if( EbmlId( *el ) == KaxSeek::ClassInfos.GlobalId )
                {
                    EbmlId id = EbmlVoid::ClassInfos.GlobalId;
                    int64_t i_pos = -1;

                    //msg_Dbg( p_input, "|   |   + Seek" );
                    p_sys->ep->Down();
                    while( ( el = p_sys->ep->Get() ) != NULL )
                    {
                        if( EbmlId( *el ) == KaxSeekID::ClassInfos.GlobalId )
                        {
                            KaxSeekID &sid = *(KaxSeekID*)el;

                            sid.ReadData( p_sys->es->I_O() );

                            id = EbmlId( sid.GetBuffer(), sid.GetSize() );
                        }
                        else  if( EbmlId( *el ) == KaxSeekPosition::ClassInfos.GlobalId )
                        {
                            KaxSeekPosition &spos = *(KaxSeekPosition*)el;

                            spos.ReadData( p_sys->es->I_O() );

                            i_pos = uint64( spos );
                        }
                        else
                        {
Laurent Aimar's avatar
Laurent Aimar committed
897
898
                            msg_Dbg( p_input, "|   |   |   + Unknown (%s)",
                                     typeid(*el).name() );
899
900
901
902
903
904
905
906
                        }
                    }
                    p_sys->ep->Up();

                    if( i_pos >= 0 )
                    {
                        if( id == KaxCues::ClassInfos.GlobalId )
                        {
Laurent Aimar's avatar
Laurent Aimar committed
907
908
                            msg_Dbg( p_input, "|   |   |   = cues at "I64Fd,
                                     i_pos );
909
910
911
912
                            p_sys->i_cues_position = p_sys->segment->GetGlobalPosition( i_pos );
                        }
                        else if( id == KaxChapters::ClassInfos.GlobalId )
                        {
Laurent Aimar's avatar
Laurent Aimar committed
913
914
                            msg_Dbg( p_input, "|   |   |   = chapters at "I64Fd,
                                     i_pos );
915
916
                            p_sys->i_chapters_position = p_sys->segment->GetGlobalPosition( i_pos );
                        }
917
918
                        else if( id == KaxTags::ClassInfos.GlobalId )
                        {
Laurent Aimar's avatar
Laurent Aimar committed
919
920
                            msg_Dbg( p_input, "|   |   |   = tags at "I64Fd,
                                     i_pos );
921
922
923
                            p_sys->i_tags_position = p_sys->segment->GetGlobalPosition( i_pos );
                        }

924
925
926
927
                    }
                }
                else
                {
Laurent Aimar's avatar
Laurent Aimar committed
928
929
                    msg_Dbg( p_input, "|   |   + Unknown (%s)",
                             typeid(*el).name() );
930
931
932
                }
            }
            p_sys->ep->Up();
933
934
935
936
937
938
939
940
        }
        else if( EbmlId( *el1 ) == KaxCues::ClassInfos.GlobalId )
        {
            msg_Dbg( p_input, "|   + Cues" );
        }
        else if( EbmlId( *el1 ) == KaxCluster::ClassInfos.GlobalId )
        {
            msg_Dbg( p_input, "|   + Cluster" );
941

942
943
            p_sys->cluster = (KaxCluster*)el1;

944
            p_sys->ep->Down();
945
946
947
            /* stop parsing the stream */
            break;
        }
948
949
950
#ifdef HAVE_MATROSKA_KAXATTACHMENTS_H
        else if( EbmlId( *el1 ) == KaxAttachments::ClassInfos.GlobalId )
#else
951
        else if( EbmlId( *el1 ) == KaxAttachements::ClassInfos.GlobalId )
952
#endif
953
        {
954
            msg_Dbg( p_input, "|   + Attachments FIXME TODO (but probably never supported)" );
955
956
957
958
959
960
961
962
963
964
965
        }
        else if( EbmlId( *el1 ) == KaxChapters::ClassInfos.GlobalId )
        {
            msg_Dbg( p_input, "|   + Chapters FIXME TODO" );
        }
        else if( EbmlId( *el1 ) == KaxTag::ClassInfos.GlobalId )
        {
            msg_Dbg( p_input, "|   + Tags FIXME TODO" );
        }
        else
        {
Laurent Aimar's avatar
Laurent Aimar committed
966
            msg_Dbg( p_input, "|   + Unknown (%s)", typeid(*el1).name() );
967
968
969
970
971
972
973
974
975
        }
    }

    if( p_sys->cluster == NULL )
    {
        msg_Err( p_input, "cannot find any cluster, damaged file ?" );
        goto error;
    }

976
977
978
979
980
981
    if( p_sys->i_chapters_position >= 0 )
    {
        msg_Warn( p_input, "chapters unsupported" );
    }

    /* *** Load the cue if found *** */
Laurent Aimar's avatar
Laurent Aimar committed
982
    if( p_sys->i_cues_position >= 0 )
983
    {
Laurent Aimar's avatar
Laurent Aimar committed
984
985
        vlc_bool_t b_seekable;

986
        stream_Control( p_input->s, STREAM_CAN_FASTSEEK, &b_seekable );
Laurent Aimar's avatar
Laurent Aimar committed
987
988
989
990
        if( b_seekable )
        {
            LoadCues( p_input );
        }
991
992
    }

993
    if( !p_sys->b_cues || p_sys->i_index <= 0 )
994
    {
Laurent Aimar's avatar
Laurent Aimar committed
995
        msg_Warn( p_input, "no cues/empty cues found->seek won't be precise" );
996
997
998
999

        IndexAppendCluster( p_input, p_sys->cluster );

        p_sys->b_cues = VLC_FALSE;
1000
1001
    }

1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
    /* Create one program */
    vlc_mutex_lock( &p_input->stream.stream_lock );
    if( input_InitStream( p_input, 0 ) == -1)
    {
        vlc_mutex_unlock( &p_input->stream.stream_lock );
        msg_Err( p_input, "cannot init stream" );
        goto error;
    }
    if( input_AddProgram( p_input, 0, 0) == NULL )
    {
        vlc_mutex_unlock( &p_input->stream.stream_lock );
        msg_Err( p_input, "cannot add program" );
        goto error;
    }
    p_input->stream.p_selected_program = p_input->stream.pp_programs[0];
Laurent Aimar's avatar
Laurent Aimar committed
1017
1018
1019
    p_input->stream.i_mux_rate = 0;
    vlc_mutex_unlock( &p_input->stream.stream_lock );

1020
1021
1022
    if( p_sys->f_duration > 1001.0 )
    {
        mtime_t i_duration = (mtime_t)( p_sys->f_duration / 1000.0 );
1023
        p_input->stream.i_mux_rate = stream_Size( p_input->s )/50 / i_duration;
1024
    }
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041

    /* add all es */
    msg_Dbg( p_input, "found %d es", p_sys->i_track );
    for( i_track = 0; i_track < p_sys->i_track; i_track++ )
    {
#define tk  p_sys->track[i_track]
        if( tk.i_cat == UNKNOWN_ES )
        {
            msg_Warn( p_input, "invalid track[%d, n=%d]", i_track, tk.i_number );
            tk.p_es = NULL;
            continue;
        }
        tk.p_es = input_AddES( p_input,
                               p_input->stream.p_selected_program,
                               i_track + 1,
                               tk.i_cat,
                               tk.psz_language, 0 );
1042
1043
1044
1045
1046
1047
1048
        if( tk.i_cat == SPU_ES )
        {
            vlc_value_t val;
            val.psz_string = "UTF-8";
#if defined(HAVE_ICONV)
            var_Create( p_input, "subsdec-encoding", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
            var_Set( p_input, "subsdec-encoding", val );
1049
#endif
1050
        }
1051
1052
        if( !strcmp( tk.psz_codec, "V_MS/VFW/FOURCC" ) )
        {
1053
            if( tk.i_extra_data < (int)sizeof( BITMAPINFOHEADER ) )
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
            {
                msg_Err( p_input, "missing/invalid BITMAPINFOHEADER" );
                tk.i_codec = VLC_FOURCC( 'u', 'n', 'd', 'f' );
            }
            else
            {
                BITMAPINFOHEADER *p_bih = (BITMAPINFOHEADER*)tk.p_extra_data;

                p_bih->biSize           = GetDWLE( &p_bih->biSize );
                p_bih->biWidth          = GetDWLE( &p_bih->biWidth );
                p_bih->biHeight         = GetDWLE( &p_bih->biHeight );
                p_bih->biPlanes         = GetWLE( &p_bih->biPlanes );
                p_bih->biBitCount       = GetWLE( &p_bih->biBitCount );
                p_bih->biCompression    = GetFOURCC( &p_bih->biCompression );
                p_bih->biSizeImage      = GetDWLE( &p_bih->biSizeImage );
                p_bih->biXPelsPerMeter  = GetDWLE( &p_bih->biXPelsPerMeter );
                p_bih->biYPelsPerMeter  = GetDWLE( &p_bih->biYPelsPerMeter );
                p_bih->biClrUsed        = GetDWLE( &p_bih->biClrUsed );
                p_bih->biClrImportant   = GetDWLE( &p_bih->biClrImportant );


                tk.i_codec = p_bih->biCompression;
                tk.p_es->p_bitmapinfoheader = p_bih;
            }
        }
        else if( !strcmp( tk.psz_codec, "V_MPEG1" ) ||
                 !strcmp( tk.psz_codec, "V_MPEG2" ) )
        {
            tk.i_codec = VLC_FOURCC( 'm', 'p', 'g', 'v' );
        }
        else if( !strncmp( tk.psz_codec, "V_MPEG4", 7 ) )
        {
            BITMAPINFOHEADER *p_bih;

            tk.i_extra_data = sizeof( BITMAPINFOHEADER );
            tk.p_extra_data = (uint8_t*)malloc( tk.i_extra_data );

            p_bih = (BITMAPINFOHEADER*)tk.p_extra_data;
            memset( p_bih, 0, sizeof( BITMAPINFOHEADER ) );
            p_bih->biSize  = sizeof( BITMAPINFOHEADER );
            p_bih->biWidth = tk.i_width;
            p_bih->biHeight= tk.i_height;

            if( !strcmp( tk.psz_codec, "V_MPEG4/MS/V3" ) )
            {
                tk.i_codec = VLC_FOURCC( 'D', 'I', 'V', '3' );
            }
            else
            {
                tk.i_codec = VLC_FOURCC( 'm', 'p', '4', 'v' );
            }
        }
        else if( !strcmp( tk.psz_codec, "A_MS/ACM" ) )
        {
1108
            if( tk.i_extra_data < (int)sizeof( WAVEFORMATEX ) )
1109
1110
1111
1112
1113
1114
1115
1116
            {
                msg_Err( p_input, "missing/invalid WAVEFORMATEX" );
                tk.i_codec = VLC_FOURCC( 'u', 'n', 'd', 'f' );
            }
            else
            {
                WAVEFORMATEX *p_wf = (WAVEFORMATEX*)tk.p_extra_data;

1117
1118
1119
1120
1121
1122
1123
                p_wf->wFormatTag        = GetWLE( &p_wf->wFormatTag );
                p_wf->nChannels         = GetWLE( &p_wf->nChannels );
                p_wf->nSamplesPerSec    = GetDWLE( &p_wf->nSamplesPerSec );
                p_wf->nAvgBytesPerSec   = GetDWLE( &p_wf->nAvgBytesPerSec );
                p_wf->nBlockAlign       = GetWLE( &p_wf->nBlockAlign );
                p_wf->wBitsPerSample    = GetWLE( &p_wf->wBitsPerSample );
                p_wf->cbSize            = GetWLE( &p_wf->cbSize );
1124

1125
                wf_tag_to_fourcc( p_wf->wFormatTag, &tk.i_codec, NULL );
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
                tk.p_es->p_waveformatex = p_wf;
            }
        }
        else if( !strcmp( tk.psz_codec, "A_MPEG/L3" ) ||
                 !strcmp( tk.psz_codec, "A_MPEG/L2" ) ||
                 !strcmp( tk.psz_codec, "A_MPEG/L1" ) )
        {
            tk.i_codec = VLC_FOURCC( 'm', 'p', 'g', 'a' );
        }
        else if( !strcmp( tk.psz_codec, "A_AC3" ) )
        {
            tk.i_codec = VLC_FOURCC( 'a', '5', '2', ' ' );
        }
        else if( !strcmp( tk.psz_codec, "A_DTS" ) )
        {
            tk.i_codec = VLC_FOURCC( 'd', 't', 's', ' ' );
        }
        else if( !strcmp( tk.psz_codec, "A_VORBIS" ) )
        {
            tk.i_codec = VLC_FOURCC( 'v', 'o', 'r', 'b' );
            tk.i_data_init = tk.i_extra_data;
            tk.p_data_init = tk.p_extra_data;
        }
        else if( !strncmp( tk.psz_codec, "A_AAC/MPEG2/", strlen( "A_AAC/MPEG2/" ) ) ||
                 !strncmp( tk.psz_codec, "A_AAC/MPEG4/", strlen( "A_AAC/MPEG4/" ) ) )
        {
            int i_profile, i_srate;
            static int i_sample_rates[] =
            {
                    96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050,
                        16000, 12000, 11025, 8000,  7350,  0,     0,     0
            };
            WAVEFORMATEX *p_wf;

            tk.i_codec = VLC_FOURCC( 'm', 'p', '4', 'a' );
            /* create data for faad (MP4DecSpecificDescrTag)*/

            if( !strcmp( &tk.psz_codec[12], "MAIN" ) )
            {
                i_profile = 0;
            }
            else if( !strcmp( &tk.psz_codec[12], "LC" ) )
            {
                i_profile = 1;
            }
            else if( !strcmp( &tk.psz_codec[12], "SSR" ) )
            {
                i_profile = 2;
            }
            else
            {
                i_profile = 3;
            }

            for( i_srate = 0; i_srate < 13; i_srate++ )
            {
                if( i_sample_rates[i_srate] == tk.i_samplerate )
                {
                    break;
                }
            }
            msg_Dbg( p_input, "profile=%d srate=%d", i_profile, i_srate );

            tk.i_extra_data = sizeof( WAVEFORMATEX ) + 2;
            tk.p_extra_data = (uint8_t*)malloc( tk.i_extra_data );
            p_wf = (WAVEFORMATEX*)tk.p_extra_data;

            p_wf->wFormatTag = WAVE_FORMAT_UNKNOWN;
            p_wf->nChannels  = tk.i_channels;
            p_wf->nSamplesPerSec = tk.i_samplerate;
            p_wf->nAvgBytesPerSec = 0;
            p_wf->nBlockAlign = 0;
            p_wf->wBitsPerSample = 0;
            p_wf->cbSize = 2;

            tk.p_extra_data[sizeof( WAVEFORMATEX )+ 0] = ((i_profile + 1) << 3) | ((i_srate&0xe) >> 1);
            tk.p_extra_data[sizeof( WAVEFORMATEX )+ 1] = ((i_srate & 0x1) << 7) | (tk.i_channels << 3);

            tk.p_es->p_waveformatex = p_wf;
        }
        else if( !strcmp( tk.psz_codec, "A_PCM/INT/BIG" ) ||
                 !strcmp( tk.psz_codec, "A_PCM/INT/LIT" ) ||
                 !strcmp( tk.psz_codec, "A_PCM/FLOAT/IEEE" ) )
        {
            WAVEFORMATEX *p_wf;

            tk.i_extra_data = sizeof( WAVEFORMATEX );
            tk.p_extra_data = (uint8_t*)malloc( tk.i_extra_data );

            p_wf = (WAVEFORMATEX*)tk.p_extra_data;

            if( !strncmp( &tk.psz_codec[6], "INT", 3 ) )
            {
                p_wf->wFormatTag = WAVE_FORMAT_PCM;
            }
            else
            {
                p_wf->wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
            }
            p_wf->nChannels  = tk.i_channels;
            p_wf->nSamplesPerSec = tk.i_samplerate;
            p_wf->nAvgBytesPerSec = 0;
            p_wf->nBlockAlign = ( tk.i_bitspersample + 7 ) / 8 * tk.i_channels;
            p_wf->wBitsPerSample = tk.i_bitspersample;
            p_wf->cbSize = 0;

            tk.p_es->p_waveformatex = p_wf;

            if( !strcmp( tk.psz_codec, "A_PCM/INT/BIG" ) )
            {
                tk.i_codec = VLC_FOURCC( 't', 'w', 'o', 's' );
            }
            else
            {
                tk.i_codec = VLC_FOURCC( 'a', 'r', 'a', 'w' );
            }
        }
        else if( !strcmp( tk.psz_codec, "S_TEXT/UTF8" ) )
        {
            tk.i_codec = VLC_FOURCC( 's', 'u', 'b', 't' );
        }
1247
1248
1249
1250
        else if( !strcmp( tk.psz_codec, "S_TEXT/SSA" ) )
        {
            tk.i_codec = VLC_FOURCC( 's', 'u', 'b', 't' );
        }
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
        else
        {
            msg_Err( p_input, "unknow codec id=`%s'", tk.psz_codec );
            tk.i_codec = VLC_FOURCC( 'u', 'n', 'd', 'f' );
        }

        tk.p_es->i_fourcc = tk.i_codec;
#undef tk
    }

    /* select track all video, one audio, no spu TODO : improve */
    b_audio_selected = VLC_FALSE;
    i_audio_channel = 0;
    i_spu_channel = 0;
    for( i_track = 0; i_track < p_sys->i_track; i_track++ )
    {
#define tk  p_sys->track[i_track]
        switch( tk.i_cat )
        {
            case VIDEO_ES:
                vlc_mutex_lock( &p_input->stream.stream_lock );
                input_SelectES( p_input, tk.p_es );
                vlc_mutex_unlock( &p_input->stream.stream_lock );
                break;

            case AUDIO_ES:
                if( ( !b_audio_selected && config_GetInt( p_input, "audio-channel" ) < 0 ) ||
                    i_audio_channel == config_GetInt( p_input, "audio-channel" ) )
                {
                    vlc_mutex_lock( &p_input->stream.stream_lock );
                    input_SelectES( p_input, tk.p_es );
                    vlc_mutex_unlock( &p_input->stream.stream_lock );

                    b_audio_selected = tk.p_es->p_decoder_fifo ? VLC_TRUE : VLC_FALSE;
                }
                i_audio_channel++;
                break;
            case SPU_ES:
                if( i_spu_channel == config_GetInt( p_input, "spu-channel" ) )
                {
                    vlc_mutex_lock( &p_input->stream.stream_lock );
                    input_SelectES( p_input, tk.p_es );
                    vlc_mutex_unlock( &p_input->stream.stream_lock );
                }
                i_spu_channel++;
                break;
        }
#undef tk
    }

    if( !b_audio_selected )
    {
        msg_Warn( p_input, "cannot find/select audio track" );
    }

1306
    /* add informations */
1307
    InformationsCreate( p_input );
1308

1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
    return VLC_SUCCESS;

error:
    delete p_sys->es;
    delete p_sys->in;
    free( p_sys );
    return VLC_EGENERIC;
}

/*****************************************************************************
Laurent Aimar's avatar
Laurent Aimar committed
1319
 * Close: frees unused data
1320
 *****************************************************************************/
Laurent Aimar's avatar
Laurent Aimar committed
1321
static void Close( vlc_object_t *p_this )
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
{
    input_thread_t *p_input = (input_thread_t *)p_this;
    demux_sys_t    *p_sys   = p_input->p_demux_data;

    int             i_track;

    for( i_track = 0; i_track < p_sys->i_track; i_track++ )
    {
#define tk  p_sys->track[i_track]
        if( tk.psz_codec )
        {
            free( tk.psz_codec );
        }
        if( tk.psz_language )
        {
            free( tk.psz_language );
        }
#undef tk
    }
    free( p_sys->track );

1343
1344
1345
1346
1347
1348
1349
1350
1351
    if( p_sys->psz_writing_application  )
    {
        free( p_sys->psz_writing_application );
    }
    if( p_sys->psz_muxing_application  )
    {
        free( p_sys->psz_muxing_application );
    }

1352
1353
    delete p_sys->segment;

1354
1355
1356
1357
1358
1359
1360
    delete p_sys->ep;
    delete p_sys->es;
    delete p_sys->in;

    free( p_sys );
}

1361
static int BlockGet( input_thread_t *p_input, KaxBlock **pp_block, int64_t *pi_ref1, int64_t *pi_ref2, int64_t *pi_duration )
1362
1363
1364
{
    demux_sys_t    *p_sys   = p_input->p_demux_data;

1365
1366
1367
    *pp_block = NULL;
    *pi_ref1  = -1;
    *pi_ref2  = -1;
1368
1369
1370
1371
1372
1373

    for( ;; )
    {
        EbmlElement *el;
        int         i_level;

1374
1375
1376
1377
1378
        if( p_input->b_die )
        {
            return VLC_EGENERIC;
        }

1379
1380
1381
        el = p_sys->ep->Get();
        i_level = p_sys->ep->GetLevel();

1382
        if( el == NULL && *pp_block != NULL )
1383
        {
1384
1385
1386
1387
1388
1389
1390
1391
            /* update the index */
#define idx p_sys->index[p_sys->i_index - 1]
            if( p_sys->i_index > 0 && idx.i_time == -1 )
            {
                idx.i_time        = (*pp_block)->GlobalTimecode() * (mtime_t) 1000 / p_sys->i_timescale;
                idx.b_key         = *pi_ref1 == -1 ? VLC_TRUE : VLC_FALSE;
            }
#undef idx
1392
            return VLC_SUCCESS;
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
        }

        if( el == NULL )
        {
            if( p_sys->ep->GetLevel() > 1 )
            {
                p_sys->ep->Up();
                continue;
            }
            msg_Warn( p_input, "EOF" );
1403
            return VLC_EGENERIC;
1404
1405
1406
1407
1408
1409
1410
1411
        }

        /* do parsing */
        if( i_level == 1 )
        {
            if( EbmlId( *el ) == KaxCluster::ClassInfos.GlobalId )
            {
                p_sys->cluster = (KaxCluster*)el;
1412
1413
1414

                /* add it to the index */
                if( p_sys->i_index == 0 ||
1415
                    ( p_sys->i_index > 0 && p_sys->index[p_sys->i_index - 1].i_position < (int64_t)p_sys->cluster->GetElementPosition() ) )
1416
1417
1418
1419
                {
                    IndexAppendCluster( p_input, p_sys->cluster );
                }

1420
1421
1422
1423
1424
                p_sys->ep->Down();
            }
            else if( EbmlId( *el ) == KaxCues::ClassInfos.GlobalId )
            {
                msg_Warn( p_input, "find KaxCues FIXME" );
1425
                return VLC_EGENERIC;
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
            }
            else
            {
                msg_Dbg( p_input, "unknown (%s)", typeid( el ).name() );
            }
        }
        else if( i_level == 2 )
        {
            if( EbmlId( *el ) == KaxClusterTimecode::ClassInfos.GlobalId )
            {
                KaxClusterTimecode &ctc = *(KaxClusterTimecode*)el;

                ctc.ReadData( p_sys->es->I_O() );
1439
                p_sys->cluster->InitTimecode( uint64( ctc ), p_sys->i_timescale );
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
            }
            else if( EbmlId( *el ) == KaxBlockGroup::ClassInfos.GlobalId )
            {
                p_sys->ep->Down();
            }
        }
        else if( i_level == 3 )
        {
            if( EbmlId( *el ) == KaxBlock::ClassInfos.GlobalId )
            {
1450
                *pp_block = (KaxBlock*)el;
1451

1452
1453
                (*pp_block)->ReadData( p_sys->es->I_O() );
                (*pp_block)->SetParent( *p_sys->cluster );
1454
1455
1456
1457
1458
1459
1460
1461

                p_sys->ep->Keep();
            }
            else if( EbmlId( *el ) == KaxBlockDuration::ClassInfos.GlobalId )
            {
                KaxBlockDuration &dur = *(KaxBlockDuration*)el;

                dur.ReadData( p_sys->es->I_O() );
1462
                *pi_duration = uint64( dur );
1463
1464
1465
1466
1467
1468
            }
            else if( EbmlId( *el ) == KaxReferenceBlock::ClassInfos.GlobalId )
            {
                KaxReferenceBlock &ref = *(KaxReferenceBlock*)el;

                ref.ReadData( p_sys->es->I_O() );
1469
                if( *pi_ref1 == -1 )