mkv.cpp 78.3 KB
Newer Older
1 2 3 4
/*****************************************************************************
 * mkv.cpp : matroska demuxer
 *****************************************************************************
 * Copyright (C) 2001 VideoLAN
5
 * $Id: mkv.cpp,v 1.45 2003/11/27 04:11:40 fenrir 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 */
Laurent Aimar's avatar
Laurent Aimar committed
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
    vlc_bool_t  b_default;
175
    vlc_bool_t  b_enabled;
176
    int         i_number;
177

178 179
    int         i_extra_data;
    uint8_t     *p_extra_data;
180

181
    char         *psz_codec;
182

183
    uint64_t     i_default_duration;
184
    float        f_timecodescale;
Laurent Aimar's avatar
Laurent Aimar committed
185

186
    /* video */
Laurent Aimar's avatar
Laurent Aimar committed
187
    es_format_t fmt;
188
    float       f_fps;
Laurent Aimar's avatar
Laurent Aimar committed
189
    es_out_id_t *p_es;
190

191 192 193 194
    vlc_bool_t      b_inited;
    /* data to be send first */
    int             i_data_init;
    uint8_t         *p_data_init;
195

196 197
    /* hack : it's for seek */
    vlc_bool_t      b_search_keyframe;
198 199 200 201 202 203 204 205

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

206
} mkv_track_t;
207

208
typedef struct
209
{
210 211
    int     i_track;
    int     i_block_number;
212

213 214
    int64_t i_position;
    int64_t i_time;
215

216 217
    vlc_bool_t b_key;
} mkv_index_t;
218

219
struct demux_sys_t
220
{
221 222 223
    vlc_stream_io_callback  *in;
    EbmlStream              *es;
    EbmlParser              *ep;
224

225 226
    /* time scale */
    uint64_t                i_timescale;
227

228 229
    /* duration of the segment */
    float                   f_duration;
230

231 232 233
    /* all tracks */
    int                     i_track;
    mkv_track_t             *track;
234

235 236 237 238
    /* from seekhead */
    int64_t                 i_cues_position;
    int64_t                 i_chapters_position;
    int64_t                 i_tags_position;
239

240 241 242
    /* current data */
    KaxSegment              *segment;
    KaxCluster              *cluster;
243

244
    mtime_t                 i_pts;
245

246 247 248 249
    vlc_bool_t              b_cues;
    int                     i_index;
    int                     i_index_max;
    mkv_index_t             *index;
250

251 252 253 254 255 256
    /* info */
    char                    *psz_muxing_application;
    char                    *psz_writing_application;
    char                    *psz_segment_filename;
    char                    *psz_title;
    char                    *psz_date_utc;
257 258
};

259 260 261 262 263 264 265
#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 );

Laurent Aimar's avatar
Laurent Aimar committed
266 267
static char *LanguageGetName    ( const char *psz_code );

268
/*****************************************************************************
Laurent Aimar's avatar
Laurent Aimar committed
269
 * Open: initializes matroska demux structures
270
 *****************************************************************************/
Laurent Aimar's avatar
Laurent Aimar committed
271
static int Open( vlc_object_t * p_this )
272
{
273 274 275
    input_thread_t *p_input = (input_thread_t *)p_this;
    demux_sys_t    *p_sys;
    uint8_t        *p_peek;
276

277
    int             i_track;
278

279 280 281 282
    EbmlElement     *el = NULL, *el1 = NULL, *el2 = NULL, *el3 = NULL, *el4 = NULL;

    /* Set the demux function */
    p_input->pf_demux = Demux;
283
    p_input->pf_demux_control = demux_vaControlDefault;
284

285 286
    /* peek the begining */
    if( input_Peek( p_input, &p_peek, 4 ) < 4 )
287 288 289 290 291 292
    {
        msg_Warn( p_input, "cannot peek" );
        return VLC_EGENERIC;
    }

    /* is a valid file */
Laurent Aimar's avatar
Laurent Aimar committed
293 294
    if( p_peek[0] != 0x1a || p_peek[1] != 0x45 ||
        p_peek[2] != 0xdf || p_peek[3] != 0xa3 )
295
    {
296 297 298
        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] );
299 300 301
        return VLC_EGENERIC;
    }

Laurent Aimar's avatar
Laurent Aimar committed
302
    p_input->p_demux_data = p_sys = (demux_sys_t*)malloc(sizeof( demux_sys_t ));
303 304
    memset( p_sys, 0, sizeof( demux_sys_t ) );

305
    p_sys->in = new vlc_stream_io_callback( p_input->s );
306 307
    p_sys->es = new EbmlStream( *p_sys->in );
    p_sys->f_duration   = -1;
308
    p_sys->i_timescale     = MKVD_TIMECODESCALE;
309 310
    p_sys->i_track      = 0;
    p_sys->track        = (mkv_track_t*)malloc( sizeof( mkv_track_t ) );
311 312 313
    p_sys->i_pts   = 0;
    p_sys->i_cues_position = -1;
    p_sys->i_chapters_position = -1;
314
    p_sys->i_tags_position = -1;
315

316
    p_sys->b_cues       = VLC_FALSE;
317 318
    p_sys->i_index      = 0;
    p_sys->i_index_max  = 1024;
Laurent Aimar's avatar
Laurent Aimar committed
319 320
    p_sys->index        = (mkv_index_t*)malloc( sizeof( mkv_index_t ) *
                                                p_sys->i_index_max );
321

322 323 324 325 326 327
    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;;

328 329 330 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 365 366 367 368 369 370 371 372 373
    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() );
374
                    p_sys->i_timescale = uint64(tcs);
375

Gildas Bazin's avatar
 
Gildas Bazin committed
376 377
                    msg_Dbg( p_input, "|   |   + TimecodeScale="I64Fd,
                             p_sys->i_timescale );
378 379 380 381 382 383 384 385
                }
                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
386 387
                    msg_Dbg( p_input, "|   |   + Duration=%f",
                             p_sys->f_duration );
388
                }
389
                else if( EbmlId( *el2 ) == KaxMuxingApp::ClassInfos.GlobalId )
390
                {
391 392 393 394 395 396
                    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
397 398
                    msg_Dbg( p_input, "|   |   + Muxing Application=%s",
                             p_sys->psz_muxing_application );
399
                }
400 401 402 403 404 405 406 407
                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
408 409
                    msg_Dbg( p_input, "|   |   + Wrinting Application=%s",
                             p_sys->psz_writing_application );
410 411 412 413 414 415 416 417 418
                }
                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
419 420
                    msg_Dbg( p_input, "|   |   + Segment Filename=%s",
                             p_sys->psz_segment_filename );
421 422 423 424 425 426 427 428 429 430 431
                }
                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 );
                }
432
#ifdef HAVE_GMTIME_R
433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454
                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
455
                    msg_Dbg( p_input, "|   |   + Unknown (%s)", typeid(*el2).name() );
456 457
                }
            }
458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474
            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 ) );
Laurent Aimar's avatar
Laurent Aimar committed
475 476 477 478

                    es_format_Init( &tk.fmt, UNKNOWN_ES, 0 );
                    tk.fmt.psz_language = strdup("English");

479 480
                    tk.b_default = VLC_TRUE;
                    tk.b_enabled = VLC_TRUE;
481 482 483 484 485
                    tk.i_number = p_sys->i_track - 1;
                    tk.i_extra_data = 0;
                    tk.p_extra_data = NULL;
                    tk.psz_codec = NULL;
                    tk.i_default_duration = 0;
486
                    tk.f_timecodescale = 1.0;
487 488 489 490 491

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

492 493 494 495 496 497
                    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;

498 499 500 501 502 503 504 505 506 507
                    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
508 509
                            msg_Dbg( p_input, "|   |   |   + Track Number=%u",
                                     uint32( tnum ) );
510 511 512 513 514 515
                        }
                        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
516 517
                            msg_Dbg( p_input, "|   |   |   + Track UID=%u",
                                     uint32( tuid ) );
518 519 520 521 522 523 524 525 526 527
                        }
                        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";
Laurent Aimar's avatar
Laurent Aimar committed
528
                                    tk.fmt.i_cat = AUDIO_ES;
529 530 531
                                    break;
                                case track_video:
                                    psz_type = "video";
Laurent Aimar's avatar
Laurent Aimar committed
532
                                    tk.fmt.i_cat = VIDEO_ES;
533 534 535
                                    break;
                                case track_subtitle:
                                    psz_type = "subtitle";
Laurent Aimar's avatar
Laurent Aimar committed
536
                                    tk.fmt.i_cat = SPU_ES;
537 538 539
                                    break;
                                default:
                                    psz_type = "unknown";
Laurent Aimar's avatar
Laurent Aimar committed
540
                                    tk.fmt.i_cat = UNKNOWN_ES;
541 542 543
                                    break;
                            }

Laurent Aimar's avatar
Laurent Aimar committed
544 545
                            msg_Dbg( p_input, "|   |   |   + Track Type=%s",
                                     psz_type );
546
                        }
547
                        else  if( EbmlId( *el3 ) == KaxTrackFlagEnabled::ClassInfos.GlobalId )
548
                        {
549 550
                            KaxTrackFlagEnabled &fenb = *(KaxTrackFlagEnabled*)el3;
                            fenb.ReadData( p_sys->es->I_O() );
551

552
                            tk.b_enabled = uint32( fenb );
Laurent Aimar's avatar
Laurent Aimar committed
553 554
                            msg_Dbg( p_input, "|   |   |   + Track Enabled=%u",
                                     uint32( fenb )  );
555 556 557 558 559
                        }
                        else  if( EbmlId( *el3 ) == KaxTrackFlagDefault::ClassInfos.GlobalId )
                        {
                            KaxTrackFlagDefault &fdef = *(KaxTrackFlagDefault*)el3;
                            fdef.ReadData( p_sys->es->I_O() );
560

561
                            tk.b_default = uint32( fdef );
Laurent Aimar's avatar
Laurent Aimar committed
562 563
                            msg_Dbg( p_input, "|   |   |   + Track Default=%u",
                                     uint32( fdef )  );
564 565 566 567 568
                        }
                        else  if( EbmlId( *el3 ) == KaxTrackFlagLacing::ClassInfos.GlobalId )
                        {
                            KaxTrackFlagLacing &lac = *(KaxTrackFlagLacing*)el3;
                            lac.ReadData( p_sys->es->I_O() );
569

Laurent Aimar's avatar
Laurent Aimar committed
570 571
                            msg_Dbg( p_input, "|   |   |   + Track Lacing=%d",
                                     uint32( lac ) );
572 573 574 575 576
                        }
                        else  if( EbmlId( *el3 ) == KaxTrackMinCache::ClassInfos.GlobalId )
                        {
                            KaxTrackMinCache &cmin = *(KaxTrackMinCache*)el3;
                            cmin.ReadData( p_sys->es->I_O() );
577

Laurent Aimar's avatar
Laurent Aimar committed
578 579
                            msg_Dbg( p_input, "|   |   |   + Track MinCache=%d",
                                     uint32( cmin ) );
580 581 582 583 584
                        }
                        else  if( EbmlId( *el3 ) == KaxTrackMaxCache::ClassInfos.GlobalId )
                        {
                            KaxTrackMaxCache &cmax = *(KaxTrackMaxCache*)el3;
                            cmax.ReadData( p_sys->es->I_O() );
585

Laurent Aimar's avatar
Laurent Aimar committed
586 587
                            msg_Dbg( p_input, "|   |   |   + Track MaxCache=%d",
                                     uint32( cmax ) );
588 589 590 591 592 593 594
                        }
                        else  if( EbmlId( *el3 ) == KaxTrackDefaultDuration::ClassInfos.GlobalId )
                        {
                            KaxTrackDefaultDuration &defd = *(KaxTrackDefaultDuration*)el3;
                            defd.ReadData( p_sys->es->I_O() );

                            tk.i_default_duration = uint64(defd);
Gildas Bazin's avatar
 
Gildas Bazin committed
595
                            msg_Dbg( p_input, "|   |   |   + Track Default Duration="I64Fd, uint64(defd) );
596 597 598 599 600 601 602 603 604 605 606 607 608 609 610
                        }
                        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 ) );
Laurent Aimar's avatar
Laurent Aimar committed
611 612
                            msg_Dbg( p_input, "|   |   |   + Track Name=%s",
                                     tk.psz_name );
613 614 615 616 617 618
                        }
                        else  if( EbmlId( *el3 ) == KaxTrackLanguage::ClassInfos.GlobalId )
                        {
                            KaxTrackLanguage &lang = *(KaxTrackLanguage*)el3;
                            lang.ReadData( p_sys->es->I_O() );

Laurent Aimar's avatar
Laurent Aimar committed
619
                            tk.fmt.psz_language =
Laurent Aimar's avatar
Laurent Aimar committed
620 621 622
                                LanguageGetName( string( lang ).c_str() );
                            msg_Dbg( p_input,
                                     "|   |   |   + Track Language=`%s'(%s) ",
Laurent Aimar's avatar
Laurent Aimar committed
623
                                     tk.fmt.psz_language, string( lang ).c_str() );
624 625 626 627 628 629 630
                        }
                        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() );
Laurent Aimar's avatar
Laurent Aimar committed
631 632
                            msg_Dbg( p_input, "|   |   |   + Track CodecId=%s",
                                     string( codecid ).c_str() );
633 634 635 636 637 638 639 640 641 642 643
                        }
                        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 );
644
                            }
Gildas Bazin's avatar
 
Gildas Bazin committed
645
                            msg_Dbg( p_input, "|   |   |   + Track CodecPrivate size="I64Fd, cpriv.GetSize() );
646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 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
                        }
                        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 ) );
692 693 694 695 696 697 698 699 700 701
                        }
                        else  if( EbmlId( *el3 ) == KaxTrackVideo::ClassInfos.GlobalId )
                        {
                            msg_Dbg( p_input, "|   |   |   + Track Video" );
                            tk.f_fps = 0.0;

                            p_sys->ep->Down();

                            while( ( el4 = p_sys->ep->Get() ) != NULL )
                            {
702 703 704 705 706 707 708 709 710 711 712 713 714 715 716
                                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 )
717 718 719 720
                                {
                                    KaxVideoPixelWidth &vwidth = *(KaxVideoPixelWidth*)el4;
                                    vwidth.ReadData( p_sys->es->I_O() );

Laurent Aimar's avatar
Laurent Aimar committed
721
                                    tk.fmt.video.i_width = uint16( vwidth );
722 723 724 725 726 727 728
                                    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() );

Laurent Aimar's avatar
Laurent Aimar committed
729
                                    tk.fmt.video.i_height = uint16( vheight );
730 731 732 733 734 735 736
                                    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() );

Gildas Bazin's avatar
 
Gildas Bazin committed
737
                                    tk.fmt.video.i_visible_width = uint16( vwidth );
738 739 740 741 742 743 744
                                    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() );

Gildas Bazin's avatar
 
Gildas Bazin committed
745
                                    tk.fmt.video.i_visible_height = uint16( vheight );
746 747 748 749 750 751 752 753 754 755
                                    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 ) );
                                }
756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777
                                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 ) );
                                }
778 779
                                else
                                {
Laurent Aimar's avatar
Laurent Aimar committed
780
                                    msg_Dbg( p_input, "|   |   |   |   + Unknown (%s)", typeid(*el4).name() );
781 782 783 784
                                }
                            }
                            p_sys->ep->Up();
                        }
785
                        else  if( EbmlId( *el3 ) == KaxTrackAudio::ClassInfos.GlobalId )
786
                        {
787
                            msg_Dbg( p_input, "|   |   |   + Track Audio" );
788

789
                            p_sys->ep->Down();
790

791
                            while( ( el4 = p_sys->ep->Get() ) != NULL )
792
                            {
793 794 795 796
                                if( EbmlId( *el4 ) == KaxAudioSamplingFreq::ClassInfos.GlobalId )
                                {
                                    KaxAudioSamplingFreq &afreq = *(KaxAudioSamplingFreq*)el4;
                                    afreq.ReadData( p_sys->es->I_O() );
797

Gildas Bazin's avatar
 
Gildas Bazin committed
798 799
                                    tk.fmt.audio.i_rate = (int)float( afreq );
                                    msg_Dbg( p_input, "|   |   |   |   + afreq=%d", tk.fmt.audio.i_rate );
800 801 802 803 804
                                }
                                else if( EbmlId( *el4 ) == KaxAudioChannels::ClassInfos.GlobalId )
                                {
                                    KaxAudioChannels &achan = *(KaxAudioChannels*)el4;
                                    achan.ReadData( p_sys->es->I_O() );
805

Laurent Aimar's avatar
Laurent Aimar committed
806
                                    tk.fmt.audio.i_channels = uint8( achan );
807 808 809 810 811 812
                                    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() );
813

Laurent Aimar's avatar
Laurent Aimar committed
814
                                    tk.fmt.audio.i_bitspersample = uint8( abits );
815 816 817 818 819 820 821 822
                                    msg_Dbg( p_input, "|   |   |   |   + abits=%u", uint8( abits ) );
                                }
                                else
                                {
                                    msg_Dbg( p_input, "|   |   |   |   + Unknown (%s)", typeid(*el4).name() );
                                }
                            }
                            p_sys->ep->Up();
823 824 825
                        }
                        else
                        {
Laurent Aimar's avatar
Laurent Aimar committed
826 827
                            msg_Dbg( p_input, "|   |   |   + Unknown (%s)",
                                     typeid(*el3).name() );
828 829 830 831 832 833
                        }
                    }
                    p_sys->ep->Up();
                }
                else
                {
Laurent Aimar's avatar
Laurent Aimar committed
834 835
                    msg_Dbg( p_input, "|   |   + Unknown (%s)",
                             typeid(*el2).name() );
836 837 838 839 840 841 842 843
                }
#undef tk
            }
            p_sys->ep->Up();
        }
        else if( EbmlId( *el1 ) == KaxSeekHead::ClassInfos.GlobalId )
        {
            msg_Dbg( p_input, "|   + Seek head" );
844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873
            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
874 875
                            msg_Dbg( p_input, "|   |   |   + Unknown (%s)",
                                     typeid(*el).name() );
876 877 878 879 880 881 882 883
                        }
                    }
                    p_sys->ep->Up();

                    if( i_pos >= 0 )
                    {
                        if( id == KaxCues::ClassInfos.GlobalId )
                        {
Laurent Aimar's avatar
Laurent Aimar committed
884 885
                            msg_Dbg( p_input, "|   |   |   = cues at "I64Fd,
                                     i_pos );
886 887 888 889
                            p_sys->i_cues_position = p_sys->segment->GetGlobalPosition( i_pos );
                        }
                        else if( id == KaxChapters::ClassInfos.GlobalId )
                        {
Laurent Aimar's avatar
Laurent Aimar committed
890 891
                            msg_Dbg( p_input, "|   |   |   = chapters at "I64Fd,
                                     i_pos );
892 893
                            p_sys->i_chapters_position = p_sys->segment->GetGlobalPosition( i_pos );
                        }
894 895
                        else if( id == KaxTags::ClassInfos.GlobalId )
                        {
Laurent Aimar's avatar
Laurent Aimar committed
896 897
                            msg_Dbg( p_input, "|   |   |   = tags at "I64Fd,
                                     i_pos );
898 899 900
                            p_sys->i_tags_position = p_sys->segment->GetGlobalPosition( i_pos );
                        }

901 902 903 904
                    }
                }
                else
                {
Laurent Aimar's avatar
Laurent Aimar committed
905 906
                    msg_Dbg( p_input, "|   |   + Unknown (%s)",
                             typeid(*el).name() );
907 908 909
                }
            }
            p_sys->ep->Up();
910 911 912 913 914 915 916 917
        }
        else if( EbmlId( *el1 ) == KaxCues::ClassInfos.GlobalId )
        {
            msg_Dbg( p_input, "|   + Cues" );
        }
        else if( EbmlId( *el1 ) == KaxCluster::ClassInfos.GlobalId )
        {
            msg_Dbg( p_input, "|   + Cluster" );
918

919 920
            p_sys->cluster = (KaxCluster*)el1;

921
            p_sys->ep->Down();
922 923 924
            /* stop parsing the stream */
            break;
        }
925 926 927
#ifdef HAVE_MATROSKA_KAXATTACHMENTS_H
        else if( EbmlId( *el1 ) == KaxAttachments::ClassInfos.GlobalId )
#else
928
        else if( EbmlId( *el1 ) == KaxAttachements::ClassInfos.GlobalId )
929
#endif
930
        {
931
            msg_Dbg( p_input, "|   + Attachments FIXME TODO (but probably never supported)" );
932 933 934 935 936 937 938 939 940 941 942
        }
        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
943
            msg_Dbg( p_input, "|   + Unknown (%s)", typeid(*el1).name() );
944 945 946 947 948 949 950 951 952
        }
    }

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

953 954 955 956 957 958
    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
959
    if( p_sys->i_cues_position >= 0 )
960
    {
Laurent Aimar's avatar
Laurent Aimar committed
961 962
        vlc_bool_t b_seekable;

963
        stream_Control( p_input->s, STREAM_CAN_FASTSEEK, &b_seekable );
Laurent Aimar's avatar
Laurent Aimar committed
964 965 966 967
        if( b_seekable )
        {
            LoadCues( p_input );
        }
968 969
    }

970
    if( !p_sys->b_cues || p_sys->i_index <= 0 )
971
    {
Laurent Aimar's avatar
Laurent Aimar committed
972
        msg_Warn( p_input, "no cues/empty cues found->seek won't be precise" );
973 974 975 976

        IndexAppendCluster( p_input, p_sys->cluster );

        p_sys->b_cues = VLC_FALSE;
977 978
    }

979 980 981 982 983 984 985 986
    /* 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;
    }
Laurent Aimar's avatar
Laurent Aimar committed
987 988 989
    p_input->stream.i_mux_rate = 0;
    vlc_mutex_unlock( &p_input->stream.stream_lock );

990 991 992
    if( p_sys->f_duration > 1001.0 )
    {
        mtime_t i_duration = (mtime_t)( p_sys->f_duration / 1000.0 );
993
        p_input->stream.i_mux_rate = stream_Size( p_input->s )/50 / i_duration;
994
    }
995 996 997 998 999 1000

    /* 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]
Laurent Aimar's avatar
Laurent Aimar committed
1001
        if( tk.fmt.i_cat == UNKNOWN_ES )
1002 1003 1004 1005 1006
        {
            msg_Warn( p_input, "invalid track[%d, n=%d]", i_track, tk.i_number );
            tk.p_es = NULL;
            continue;
        }
Laurent Aimar's avatar
Laurent Aimar committed
1007 1008

        if( tk.fmt.i_cat == SPU_ES )
1009 1010 1011 1012 1013 1014
        {
            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 );
1015
#endif
1016
        }
1017 1018
        if( !strcmp( tk.psz_codec, "V_MS/VFW/FOURCC" ) )
        {
1019
            if( tk.i_extra_data < (int)sizeof( BITMAPINFOHEADER ) )
1020 1021
            {
                msg_Err( p_input, "missing/invalid BITMAPINFOHEADER" );
Laurent Aimar's avatar
Laurent Aimar committed
1022
                tk.fmt.i_codec = VLC_FOURCC( 'u', 'n', 'd', 'f' );
1023 1024 1025 1026 1027
            }
            else
            {
                BITMAPINFOHEADER *p_bih = (BITMAPINFOHEADER*)tk.p_extra_data;

Laurent Aimar's avatar
Laurent Aimar committed
1028 1029 1030 1031 1032 1033 1034 1035 1036 1037
                tk.fmt.video.i_width = GetDWLE( &p_bih->biWidth );
                tk.fmt.video.i_height= GetDWLE( &p_bih->biHeight );
                tk.fmt.i_codec       = GetFOURCC( &p_bih->biCompression );

                tk.fmt.i_extra       = GetDWLE( &p_bih->biSize ) - sizeof( BITMAPINFOHEADER );
                if( tk.fmt.i_extra > 0 )
                {
                    tk.fmt.p_extra = malloc( tk.fmt.i_extra );
                    memcpy( tk.fmt.p_extra, &p_bih[1], tk.fmt.i_extra );
                }
1038 1039 1040 1041 1042
            }
        }
        else if( !strcmp( tk.psz_codec, "V_MPEG1" ) ||
                 !strcmp( tk.psz_codec, "V_MPEG2" ) )
        {
Laurent Aimar's avatar
Laurent Aimar committed
1043
            tk.fmt.i_codec = VLC_FOURCC( 'm', 'p', 'g', 'v' );
1044 1045 1046 1047 1048
        }
        else if( !strncmp( tk.psz_codec, "V_MPEG4", 7 ) )
        {
            if( !strcmp( tk.psz_codec, "V_MPEG4/MS/V3" ) )
            {
Laurent Aimar's avatar
Laurent Aimar committed
1049
                tk.fmt.i_codec = VLC_FOURCC( 'D', 'I', 'V', '3' );
1050 1051 1052
            }
            else
            {
Laurent Aimar's avatar
Laurent Aimar committed
1053
                tk.fmt.i_codec = VLC_FOURCC( 'm', 'p', '4', 'v' );
1054 1055 1056 1057
            }
        }
        else if( !strcmp( tk.psz_codec, "A_MS/ACM" ) )
        {
1058
            if( tk.i_extra_data < (int)sizeof( WAVEFORMATEX ) )
1059 1060
            {
                msg_Err( p_input, "missing/invalid WAVEFORMATEX" );
Laurent Aimar's avatar
Laurent Aimar committed
1061
                tk.fmt.i_codec = VLC_FOURCC( 'u', 'n', 'd', 'f' );
1062 1063 1064 1065 1066
            }
            else
            {
                WAVEFORMATEX *p_wf = (WAVEFORMATEX*)tk.p_extra_data;

Laurent Aimar's avatar
Laurent Aimar committed
1067
                wf_tag_to_fourcc( GetWLE( &p_wf->wFormatTag ), &tk.fmt.i_codec, NULL );
1068

Laurent Aimar's avatar
Laurent Aimar committed
1069
                tk.fmt.audio.i_channels   = GetWLE( &p_wf->nChannels );
Gildas Bazin's avatar
 
Gildas Bazin committed
1070
                tk.fmt.audio.i_rate = GetDWLE( &p_wf->nSamplesPerSec );
Gildas Bazin's avatar
 
Gildas Bazin committed
1071
                tk.fmt.i_bitrate    = GetDWLE( &p_wf->nAvgBytesPerSec ) * 8;
Laurent Aimar's avatar
Laurent Aimar committed
1072 1073 1074 1075 1076 1077 1078 1079 1080
                tk.fmt.audio.i_blockalign = GetWLE( &p_wf->nBlockAlign );;
                tk.fmt.audio.i_bitspersample = GetWLE( &p_wf->wBitsPerSample );

                tk.fmt.i_extra            = GetWLE( &p_wf->cbSize );
                if( tk.fmt.i_extra > 0 )
                {
                    tk.fmt.p_extra = malloc( tk.fmt.i_extra );
                    memcpy( tk.fmt.p_extra, &p_wf[1], tk.fmt.i_extra );
                }
1081 1082 1083 1084 1085 1086
            }
        }
        else if( !strcmp( tk.psz_codec, "A_MPEG/L3" ) ||
                 !strcmp( tk.psz_codec, "A_MPEG/L2" ) ||
                 !strcmp( tk.psz_codec, "A_MPEG/L1" ) )
        {
Laurent Aimar's avatar
Laurent Aimar committed
1087
            tk.fmt.i_codec = VLC_FOURCC( 'm', 'p', 'g', 'a' );
1088 1089 1090
        }
        else if( !strcmp( tk.psz_codec, "A_AC3" ) )
        {
Laurent Aimar's avatar
Laurent Aimar committed
1091
            tk.fmt.i_codec = VLC_FOURCC( 'a', '5', '2', ' ' );
1092 1093 1094
        }
        else if( !strcmp( tk.psz_codec, "A_DTS" ) )
        {
Laurent Aimar's avatar
Laurent Aimar committed
1095
            tk.fmt.i_codec = VLC_FOURCC( 'd', 't', 's', ' ' );
1096 1097 1098
        }
        else if( !strcmp( tk.psz_codec, "A_VORBIS" ) )
        {