matroska_segment_parse.cpp 71.3 KB
Newer Older
1
/*****************************************************************************
Pere Orga's avatar
Pere Orga committed
2
 * matroska_segment_parse.cpp : matroska demuxer
3
 *****************************************************************************
Jean-Baptiste Kempf's avatar
LGPL  
Jean-Baptiste Kempf committed
4
 * Copyright (C) 2003-2010 VLC authors and VideoLAN
5 6 7 8 9
 * $Id$
 *
 * Authors: Laurent Aimar <fenrir@via.ecp.fr>
 *          Steve Lhomme <steve.lhomme@free.fr>
 *
Jean-Baptiste Kempf's avatar
LGPL  
Jean-Baptiste Kempf committed
10 11 12
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
13 14 15 16
 * (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
Jean-Baptiste Kempf's avatar
LGPL  
Jean-Baptiste Kempf committed
17 18
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
19
 *
Jean-Baptiste Kempf's avatar
LGPL  
Jean-Baptiste Kempf committed
20 21 22
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23
 *****************************************************************************/
24
#include "mkv.hpp"
25 26 27
#include "matroska_segment.hpp"
#include "chapters.hpp"
#include "demux.hpp"
28
#include "Ebml_parser.hpp"
29
#include "Ebml_dispatcher.hpp"
30
#include "string_dispatcher.hpp"
31 32
#include "util.hpp"

33 34
extern "C" {
#include "../vobsub.h"
35
#include "../xiph.h"
36
#include "../windows_audio_commons.h"
37
#include "../mp4/libmp4.h"
38 39 40
}

#include <vlc_codecs.h>
41
#include <stdexcept>
42
#include <limits>
43 44 45 46 47 48 49 50

/* GetFourCC helper */
#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] );
}

51 52 53 54 55 56
static inline void fill_extra_data_alac( mkv_track_t *p_tk )
{
    if( p_tk->i_extra_data <= 0 ) return;
    p_tk->fmt.p_extra = malloc( p_tk->i_extra_data + 12 );
    if( unlikely( !p_tk->fmt.p_extra ) ) return;
    p_tk->fmt.i_extra = p_tk->i_extra_data + 12;
57
    uint8_t *p_extra = static_cast<uint8_t*>( p_tk->fmt.p_extra );
58 59 60 61 62 63 64 65
    /* See "ALAC Specific Info (36 bytes) (required)" from
       alac.macosforge.org/trac/browser/trunk/ALACMagicCookieDescription.txt */
    SetDWBE( p_extra, p_tk->fmt.i_extra );
    memcpy( p_extra + 4, "alac", 4 );
    SetDWBE( p_extra + 8, 0 );
    memcpy( p_extra + 12, p_tk->p_extra_data, p_tk->fmt.i_extra - 12 );
}

66 67 68 69 70 71 72 73 74
static inline void fill_extra_data( mkv_track_t *p_tk, unsigned int offset )
{
    if(p_tk->i_extra_data <= offset) return;
    p_tk->fmt.i_extra = p_tk->i_extra_data - offset;
    p_tk->fmt.p_extra = xmalloc( p_tk->fmt.i_extra );
    if(!p_tk->fmt.p_extra) { p_tk->fmt.i_extra = 0; return; };
    memcpy( p_tk->fmt.p_extra, p_tk->p_extra_data + offset, p_tk->fmt.i_extra );
}

Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
75 76 77 78 79 80 81 82
/*****************************************************************************
 * Some functions to manipulate memory
 *****************************************************************************/
static inline char * ToUTF8( const UTFstring &u )
{
    return strdup( u.GetUTF8().c_str() );
}

83 84 85 86 87 88 89
/*****************************************************************************
 * ParseSeekHead:
 *****************************************************************************/
void matroska_segment_c::ParseSeekHead( KaxSeekHead *seekhead )
{
    EbmlElement *l;
    bool b_seekable;
90

91
    i_seekhead_count++;
92

93
    vlc_stream_Control( sys.demuxer.s, STREAM_CAN_SEEK, &b_seekable );
94 95
    if( !b_seekable )
        return;
96

97 98
    EbmlParser eparser ( &es, seekhead, &sys.demuxer,
                        var_InheritBool( &sys.demuxer, "mkv-use-dummy" ) );
99

100
    while( ( l = eparser.Get() ) != NULL )
101 102 103
    {
        if( MKV_IS_ID( l, KaxSeek ) )
        {
Steve Lhomme's avatar
Steve Lhomme committed
104
            EbmlId id = EBML_ID(EbmlVoid);
105
            int64_t i_pos = -1;
106

107
#ifdef MKV_DEBUG
108
            msg_Dbg( &sys.demuxer, "|   |   + Seek" );
109
#endif
110
            eparser.Down();
111
            try
112
            {
113
                while( ( l = eparser.Get() ) != NULL )
114
                {
115
                    if( unlikely( !l->ValidateSize() ) )
116 117 118 119
                    {
                        msg_Err( &sys.demuxer,"%s too big... skipping it",  typeid(*l).name() );
                        continue;
                    }
120 121
                    if( MKV_IS_ID( l, KaxSeekID ) )
                    {
122
                        KaxSeekID &sid = *static_cast<KaxSeekID*>( l );
123 124 125 126 127
                        sid.ReadData( es.I_O() );
                        id = EbmlId( sid.GetBuffer(), sid.GetSize() );
                    }
                    else if( MKV_IS_ID( l, KaxSeekPosition ) )
                    {
128
                        KaxSeekPosition &spos = *static_cast<KaxSeekPosition*>( l );
129
                        spos.ReadData( es.I_O() );
130
                        i_pos = (int64_t)segment->GetGlobalPosition( static_cast<uint64>( spos ) );
131
                    }
132
                    else if ( !MKV_IS_ID( l, EbmlVoid ) && !MKV_IS_ID( l, EbmlCrc32 ))
133 134 135 136
                    {
                        /* Many mkvmerge files hit this case. It seems to be a broken SeekHead */
                        msg_Dbg( &sys.demuxer, "|   |   + Unknown (%s)", typeid(*l).name() );
                    }
137 138
                }
            }
139 140 141 142
            catch(...)
            {
                msg_Err( &sys.demuxer,"Error while reading %s",  typeid(*l).name() );
            }
143
            eparser.Up();
144

145 146
            if( i_pos >= 0 )
            {
147 148 149 150 151
                if( id == EBML_ID(KaxCluster) )
                {
                    _seeker.add_cluster_position( i_pos );
                }
                else if( id == EBML_ID(KaxCues) )
152
                {
153
                    msg_Dbg( &sys.demuxer, "|   - cues at %" PRId64, i_pos );
Steve Lhomme's avatar
Steve Lhomme committed
154
                    LoadSeekHeadItem( EBML_INFO(KaxCues), i_pos );
155
                }
Steve Lhomme's avatar
Steve Lhomme committed
156
                else if( id == EBML_ID(KaxInfo) )
157
                {
158
                    msg_Dbg( &sys.demuxer, "|   - info at %" PRId64, i_pos );
Steve Lhomme's avatar
Steve Lhomme committed
159
                    LoadSeekHeadItem( EBML_INFO(KaxInfo), i_pos );
160
                }
Steve Lhomme's avatar
Steve Lhomme committed
161
                else if( id == EBML_ID(KaxChapters) )
162
                {
163
                    msg_Dbg( &sys.demuxer, "|   - chapters at %" PRId64, i_pos );
Steve Lhomme's avatar
Steve Lhomme committed
164
                    LoadSeekHeadItem( EBML_INFO(KaxChapters), i_pos );
165
                }
Steve Lhomme's avatar
Steve Lhomme committed
166
                else if( id == EBML_ID(KaxTags) )
167
                {
168
                    msg_Dbg( &sys.demuxer, "|   - tags at %" PRId64, i_pos );
Steve Lhomme's avatar
Steve Lhomme committed
169
                    LoadSeekHeadItem( EBML_INFO(KaxTags), i_pos );
170
                }
Steve Lhomme's avatar
Steve Lhomme committed
171
                else if( id == EBML_ID(KaxSeekHead) )
172
                {
173
                    msg_Dbg( &sys.demuxer, "|   - chained seekhead at %" PRId64, i_pos );
Steve Lhomme's avatar
Steve Lhomme committed
174
                    LoadSeekHeadItem( EBML_INFO(KaxSeekHead), i_pos );
175
                }
Steve Lhomme's avatar
Steve Lhomme committed
176
                else if( id == EBML_ID(KaxTracks) )
177
                {
178
                    msg_Dbg( &sys.demuxer, "|   - tracks at %" PRId64, i_pos );
Steve Lhomme's avatar
Steve Lhomme committed
179
                    LoadSeekHeadItem( EBML_INFO(KaxTracks), i_pos );
180
                }
Steve Lhomme's avatar
Steve Lhomme committed
181
                else if( id == EBML_ID(KaxAttachments) )
182
                {
183
                    msg_Dbg( &sys.demuxer, "|   - attachments at %" PRId64, i_pos );
Steve Lhomme's avatar
Steve Lhomme committed
184
                    LoadSeekHeadItem( EBML_INFO(KaxAttachments), i_pos );
185
                }
186
#ifdef MKV_DEBUG
187 188
                else if( id != EBML_ID(KaxCluster) && id != EBML_ID(EbmlVoid) &&
                         id != EBML_ID(EbmlCrc32))
189
                    msg_Dbg( &sys.demuxer, "|   - unknown seekhead reference at %" PRId64, i_pos );
190
#endif
191 192
            }
        }
193
        else if ( !MKV_IS_ID( l, EbmlVoid ) && !MKV_IS_ID( l, EbmlCrc32 ))
194 195
            msg_Dbg( &sys.demuxer, "|   |   + ParseSeekHead Unknown (%s)", typeid(*l).name() );
    }
196 197
}

198

199
/*****************************************************************************
200
 * ParseTrackEntry:
201
 *****************************************************************************/
202

203
void matroska_segment_c::ParseTrackEntry( const KaxTrackEntry *m )
204 205
{
    bool bSupported = true;
206

207
    /* Init the track */
208 209
    mkv_track_t track;

210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236
    EbmlUInteger *pTrackType = static_cast<EbmlUInteger*>(m->FindElt(EBML_INFO(KaxTrackType)));
    uint8 ttype;
    if (likely(pTrackType != NULL))
        ttype = (uint8) *pTrackType;
    else
        ttype = 0;

    switch( ttype )
    {
        case track_audio:
            es_format_Init( &track.fmt, AUDIO_ES, 0);
            track.fmt.audio.i_channels = 1;
            track.fmt.audio.i_rate = 8000;
            break;
        case track_video:
            es_format_Init( &track.fmt, VIDEO_ES, 0);
            break;
        case track_subtitle:
            es_format_Init( &track.fmt, SPU_ES, 0);
            break;
        case track_buttons:
            es_format_Init( &track.fmt, SPU_ES, 0);
            break;
        default:
            es_format_Init( &track.fmt, UNKNOWN_ES, 0);
            break;
    }
237

238
    MkvTree( sys.demuxer, 2, "Track Entry" );
239

240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256
    struct MetaDataCapture {
      matroska_segment_c * obj;
      mkv_track_t        * tk;
      demux_t            * p_demuxer;
      bool&                bSupported;
      int                  level;
      struct {
        unsigned int i_crop_right;
        unsigned int i_crop_left;
        unsigned int i_crop_top;
        unsigned int i_crop_bottom;
        unsigned int i_display_unit;
        unsigned int i_display_width;
        unsigned int i_display_height;
      } track_video_info;

    } metadata_payload = {
257
      this, &track, &sys.demuxer, bSupported, 3, { }
258 259 260
    };

    MKV_SWITCH_CREATE( EbmlTypeDispatcher, MetaDataHandlers, MetaDataCapture )
261
    {
262
        MKV_SWITCH_INIT();
263

264 265 266 267 268 269
        static void debug (MetaDataCapture const& vars, char const * fmt, ...)
        {
            va_list args; va_start( args, fmt );
            MkvTree_va( *vars.p_demuxer, vars.level, fmt, args);
            va_end( args );
        }
270
        E_CASE( KaxTrackNumber, tnum )
271
        {
272
            vars.tk->i_number = static_cast<uint32>( tnum );
273
            debug( vars, "Track Number=%u", vars.tk->i_number );
274
        }
275
        E_CASE( KaxTrackUID, tuid )
276
        {
277
            debug( vars, "Track UID=%u", static_cast<uint32>( tuid ) );
278
        }
279
        E_CASE( KaxTrackType, ttype )
280 281
        {
            const char *psz_type;
282

283
            switch( static_cast<uint8>( ttype ) )
284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300
            {
                case track_audio:
                    psz_type = "audio";
                    break;
                case track_video:
                    psz_type = "video";
                    break;
                case track_subtitle:
                    psz_type = "subtitle";
                    break;
                case track_buttons:
                    psz_type = "buttons";
                    break;
                default:
                    psz_type = "unknown";
                    break;
            }
301

302
            debug( vars, "Track Type=%s", psz_type ) ;
303
        }
304
        E_CASE( KaxTrackFlagEnabled, fenb ) // UNUSED
305
        {
306 307
            vars.tk->b_enabled = static_cast<uint32>( fenb );
            debug( vars, "Track Enabled=%u", vars.tk->b_enabled );
308
        }
309
        E_CASE( KaxTrackFlagDefault, fdef )
310
        {
311 312
            vars.tk->b_default = static_cast<uint32>( fdef );
            debug( vars, "Track Default=%u", vars.tk->b_default );
313
        }
314
        E_CASE( KaxTrackFlagForced, ffor ) // UNUSED
315
        {
316
            vars.tk->b_forced = static_cast<uint32>( ffor );
317

318
            debug( vars, "Track Forced=%u", vars.tk->b_forced );
319
        }
320
        E_CASE( KaxTrackFlagLacing, lac ) // UNUSED
321
        {
322
            debug( vars, "Track Lacing=%d", static_cast<uint32>( lac ) ) ;
323
        }
324
        E_CASE( KaxTrackMinCache, cmin ) // UNUSED
325
        {
326
            debug( vars, "Track MinCache=%d", static_cast<uint32>( cmin ) ) ;
327
        }
328
        E_CASE( KaxTrackMaxCache, cmax ) // UNUSED
329
        {
330
            debug( vars, "Track MaxCache=%d", static_cast<uint32>( cmax ) ) ;
331
        }
332
        E_CASE( KaxTrackDefaultDuration, defd )
333
        {
334 335
            vars.tk->i_default_duration = static_cast<uint64>(defd);
            debug( vars, "Track Default Duration=%" PRId64, vars.tk->i_default_duration );
336
            vars.tk->i_default_duration /= 1000;
337
        }
338
        E_CASE( KaxTrackTimecodeScale, ttcs )
339
        {
340 341
            vars.tk->f_timecodescale = static_cast<float>( ttcs );
            if ( vars.tk->f_timecodescale <= 0 ) vars.tk->f_timecodescale = 1.0;
342
            debug( vars, "Track TimeCodeScale=%f", vars.tk->f_timecodescale ) ;
343
        }
344
        E_CASE( KaxMaxBlockAdditionID, mbl ) // UNUSED
345
        {
346
            debug( vars, "Track Max BlockAdditionID=%d", static_cast<uint32>( mbl ) ) ;
347
        }
348
        E_CASE( KaxTrackName, tname )
349
        {
350
            vars.tk->fmt.psz_description = ToUTF8( UTFstring( tname ) );
351
            debug( vars, "Track Name=%s", vars.tk->fmt.psz_description ? vars.tk->fmt.psz_description : "(null)" );
352
        }
353
        E_CASE( KaxTrackLanguage, lang )
354
        {
355
            free( vars.tk->fmt.psz_language );
356
            const std::string slang ( lang );
357 358
            size_t pos = slang.find_first_of( '-' );
            vars.tk->fmt.psz_language = pos != std::string::npos ? strndup( slang.c_str (), pos ) : strdup( slang.c_str() );
359
            debug( vars, "Track Language=`%s'", vars.tk->fmt.psz_language ? vars.tk->fmt.psz_language : "(null)" );
360
        }
361
        E_CASE( KaxCodecID, codecid )
362
        {
363
            vars.tk->codec = std::string( codecid );
364
            debug( vars, "Track CodecId=%s", std::string( codecid ).c_str() ) ;
365
        }
366
        E_CASE( KaxCodecPrivate, cpriv )
367
        {
368 369
            vars.tk->i_extra_data = cpriv.GetSize();
            if( vars.tk->i_extra_data > 0 )
370
            {
371
                vars.tk->p_extra_data = static_cast<uint8_t*>( malloc( vars.tk->i_extra_data ) );
372 373 374 375

                if( likely( vars.tk->p_extra_data ) )
                    memcpy( vars.tk->p_extra_data, cpriv.GetBuffer(),
                            vars.tk->i_extra_data );
376
            }
377
            debug( vars, "Track CodecPrivate size=%" PRId64, cpriv.GetSize() );
378
        }
379
        E_CASE( KaxCodecName, cname )
380
        {
381 382
            vars.tk->str_codec_name = static_cast<UTFstring const&>( cname ).GetUTF8();
            debug( vars, "Track Codec Name=%s", vars.tk->str_codec_name.c_str() ) ;
383
        }
384
        //AttachmentLink
385
        E_CASE( KaxCodecDecodeAll, cdall ) // UNUSED
386
        {
387
            debug( vars, "Track Codec Decode All=%u", static_cast<uint8>( cdall ) ) ;
388
        }
389
        E_CASE( KaxTrackOverlay, tovr ) // UNUSED
390
        {
391
            debug( vars, "Track Overlay=%u", static_cast<uint32>( tovr ) ) ;
392
        }
393
#if LIBMATROSKA_VERSION >= 0x010401
394
        E_CASE( KaxCodecDelay, codecdelay )
395
        {
396 397 398
            vars.tk->i_codec_delay = static_cast<uint64_t>( codecdelay ) / 1000;
            msg_Dbg( vars.p_demuxer, "|   |   |   + Track Codec Delay =%" PRIu64,
                     vars.tk->i_codec_delay );
399
        }
400
        E_CASE( KaxSeekPreRoll, spr )
401
        {
402
            vars.tk->i_seek_preroll = static_cast<uint64_t>( spr ) / 1000;
403
            debug( vars, "Track Seek Preroll =%" PRIu64, vars.tk->i_seek_preroll );
404 405
        }
#endif
406
        E_CASE( KaxContentEncodings, cencs )
407
        {
408
            debug( vars, "Content Encodings" );
409 410

            if ( cencs.ListSize () > 1 )
411
            {
412 413
                msg_Err( vars.p_demuxer, "Multiple Compression method not supported" );
                vars.bSupported = false;
414
            }
415 416 417 418 419 420 421

            vars.level += 1;
            dispatcher.iterate( cencs.begin(), cencs.end(), Payload( vars ) );
            vars.level -= 1;
        }
        E_CASE( KaxContentEncoding, cenc )
        {
422
            debug( vars, "Content Encoding" );
423 424 425 426 427 428 429

            vars.level += 1;
            dispatcher.iterate( cenc.begin(), cenc.end(), Payload( vars ) );
            vars.level -= 1;
        }
        E_CASE( KaxContentEncodingOrder, encord )
        {
430
            debug( vars, "Order: %i", static_cast<uint32>( encord ) );
431 432 433 434
        }
        E_CASE( KaxContentEncodingScope, encscope )
        {
            vars.tk->i_encoding_scope = static_cast<uint32>( encscope );
435
            debug( vars, "Scope: %i", vars.tk->i_encoding_scope );
436 437 438
        }
        E_CASE( KaxContentEncodingType, enctype )
        {
439
            debug( vars, "Type: %i", static_cast<uint32>( enctype ) );
440 441 442
        }
        E_CASE( KaxContentCompression, compr )
        {
443
            debug( vars, "Content Compression" );
444 445 446 447 448 449 450 451 452 453
            //Default compression type is 0 (Zlib)
            vars.tk->i_compression_type = MATROSKA_COMPRESSION_ZLIB;

            vars.level += 1;
            dispatcher.iterate( compr.begin(), compr.end(), Payload( vars ) );
            vars.level -= 1;
        }
        E_CASE( KaxContentCompAlgo, compalg )
        {
            vars.tk->i_compression_type = static_cast<uint32>( compalg );
454
            debug( vars, "Compression Algorithm: %i", vars.tk->i_compression_type );
455 456
            if ( ( vars.tk->i_compression_type != MATROSKA_COMPRESSION_ZLIB ) &&
                 ( vars.tk->i_compression_type != MATROSKA_COMPRESSION_HEADER ) )
457
            {
458 459
                msg_Err( vars.p_demuxer, "Track Compression method %d not supported", vars.tk->i_compression_type );
                vars.bSupported = false;
460 461
            }
        }
462 463 464 465 466 467
        E_CASE( KaxContentCompSettings, kccs )
        {
            vars.tk->p_compression_data = new KaxContentCompSettings( kccs );
        }
        E_CASE( KaxTrackVideo, tkv )
        {
468 469
            debug( vars, "Track Video");

470 471
            mkv_track_t *tk = vars.tk;

472 473 474
            if (tk->fmt.i_cat != VIDEO_ES ) {
                msg_Err( vars.p_demuxer, "Video elements not allowed for this track" );
            } else {
475
            tk->f_fps = 0.0;
476 477 478 479 480 481

            if( tk->i_default_duration > 1000 ) /* Broken ffmpeg mux info when non set fps */
            {
                tk->fmt.video.i_frame_rate_base = static_cast<unsigned>( tk->i_default_duration );
                tk->fmt.video.i_frame_rate = 1000000;
            }
482

483 484 485
            vars.level += 1;
            dispatcher.iterate (tkv.begin (), tkv.end (), Payload( vars ) );
            vars.level -= 1;
486

487 488 489 490
            unsigned int i_crop_top    = vars.track_video_info.i_crop_top;
            unsigned int i_crop_right  = vars.track_video_info.i_crop_right;
            unsigned int i_crop_bottom = vars.track_video_info.i_crop_bottom;
            unsigned int i_crop_left   = vars.track_video_info.i_crop_left;
491

492 493 494
            unsigned int i_display_unit   = vars.track_video_info.i_display_unit; VLC_UNUSED(i_display_unit);
            unsigned int i_display_width  = vars.track_video_info.i_display_width;
            unsigned int i_display_height = vars.track_video_info.i_display_height;
495

496
            if( i_display_height && i_display_width )
Laurent Aimar's avatar
Laurent Aimar committed
497 498 499 500
            {
                tk->fmt.video.i_sar_num = i_display_width  * tk->fmt.video.i_height;
                tk->fmt.video.i_sar_den = i_display_height * tk->fmt.video.i_width;
            }
501

502 503
            tk->fmt.video.i_visible_width   = tk->fmt.video.i_width;
            tk->fmt.video.i_visible_height  = tk->fmt.video.i_height;
504

505 506
            if( i_crop_left || i_crop_right || i_crop_top || i_crop_bottom )
            {
507 508 509
                tk->fmt.video.i_x_offset        = i_crop_left;
                tk->fmt.video.i_y_offset        = i_crop_top;
                tk->fmt.video.i_visible_width  -= i_crop_left + i_crop_right;
510 511 512 513
                tk->fmt.video.i_visible_height -= i_crop_top + i_crop_bottom;
            }
            /* FIXME: i_display_* allows you to not only set DAR, but also a zoom factor.
               we do not support this atm */
514
            }
515
        }
516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555
#if LIBMATROSKA_VERSION >= 0x010406
        E_CASE( KaxVideoProjection, proj )
        {
            debug( vars, "Track Video Projection" ) ;

            vars.level += 1;
            dispatcher.iterate (proj.begin (), proj.end (), Payload( vars ) );
            vars.level -= 1;
        }
        E_CASE( KaxVideoProjectionType, fint )
        {
            switch (static_cast<uint8>( fint ))
            {
            case 0:
                vars.tk->fmt.video.projection_mode = PROJECTION_MODE_RECTANGULAR;
                break;
            case 1:
                vars.tk->fmt.video.projection_mode = PROJECTION_MODE_EQUIRECTANGULAR;
                break;
            case 2:
                vars.tk->fmt.video.projection_mode = PROJECTION_MODE_CUBEMAP_LAYOUT_STANDARD;
                break;
            default:
                debug( vars, "Track Video Projection %u not supported", static_cast<uint8>( fint ) ) ;
                break;
            }
        }
        E_CASE( KaxVideoProjectionPoseYaw, pose )
        {
            vars.tk->fmt.video.pose.f_yaw_degrees = static_cast<float>( pose );
        }
        E_CASE( KaxVideoProjectionPosePitch, pose )
        {
            vars.tk->fmt.video.pose.f_pitch_degrees = static_cast<float>( pose );
        }
        E_CASE( KaxVideoProjectionPoseRoll, pose )
        {
            vars.tk->fmt.video.pose.f_roll_degrees = static_cast<float>( pose );
        }
#endif
556
        E_CASE( KaxVideoFlagInterlaced, fint ) // UNUSED
557
        {
558
            debug( vars, "Track Video Interlaced=%u", static_cast<uint8>( fint ) ) ;
559 560 561
        }
        E_CASE( KaxVideoStereoMode, stereo ) // UNUSED
        {
562
            debug( vars, "Track Video Stereo Mode=%u", static_cast<uint8>( stereo ) ) ;
563 564 565 566
        }
        E_CASE( KaxVideoPixelWidth, vwidth )
        {
            vars.tk->fmt.video.i_width += static_cast<uint16>( vwidth );
567
            debug( vars, "width=%d", vars.tk->fmt.video.i_width );
568 569 570 571
        }
        E_CASE( KaxVideoPixelHeight, vheight )
        {
            vars.tk->fmt.video.i_height += static_cast<uint16>( vheight );
572
            debug( vars, "height=%d", vars.tk->fmt.video.i_height );
573 574 575 576
        }
        E_CASE( KaxVideoDisplayWidth, vwidth )
        {
            vars.track_video_info.i_display_width = static_cast<uint16>( vwidth );
577
            debug( vars, "display width=%d", vars.track_video_info.i_display_width );
578 579 580 581
        }
        E_CASE( KaxVideoDisplayHeight, vheight )
        {
            vars.track_video_info.i_display_height = static_cast<uint16>( vheight );
582
            debug( vars, "display height=%d", vars.track_video_info.i_display_height );
583 584 585 586
        }
        E_CASE( KaxVideoPixelCropBottom, cropval )
        {
            vars.track_video_info.i_crop_bottom = static_cast<uint16>( cropval );
587
            debug( vars, "crop pixel bottom=%d", vars.track_video_info.i_crop_bottom );
588 589 590 591
        }
        E_CASE( KaxVideoPixelCropTop, cropval )
        {
            vars.track_video_info.i_crop_top = static_cast<uint16>( cropval );
592
            debug( vars, "crop pixel top=%d", vars.track_video_info.i_crop_top );
593 594 595 596
        }
        E_CASE( KaxVideoPixelCropRight, cropval )
        {
            vars.track_video_info.i_crop_right = static_cast<uint16>( cropval );
597
            debug( vars, "crop pixel right=%d", vars.track_video_info.i_crop_right );
598 599 600 601
        }
        E_CASE( KaxVideoPixelCropLeft, cropval )
        {
            vars.track_video_info.i_crop_left = static_cast<uint16>( cropval );
602
            debug( vars, "crop pixel left=%d", vars.track_video_info.i_crop_left );
603 604 605 606
        }
        E_CASE( KaxVideoDisplayUnit, vdmode )
        {
            vars.track_video_info.i_display_unit = static_cast<uint8>( vdmode );
607 608
            debug( vars, "Track Video Display Unit=%s",
                vars.track_video_info.i_display_unit == 0 ? "pixels" : ( vars.track_video_info.i_display_unit == 1 ? "centimeters": "inches" ) );
609 610 611
        }
        E_CASE( KaxVideoAspectRatio, ratio ) // UNUSED
        {
612
            debug( vars, "Track Video Aspect Ratio Type=%u", static_cast<uint8>( ratio ) ) ;
613 614 615
        }
        E_CASE( KaxVideoFrameRate, vfps )
        {
616 617
            vars.tk->f_fps = __MAX( static_cast<float>( vfps ), 1 );
            debug( vars, "fps=%f", vars.tk->f_fps );
618
        }
Tim Allen's avatar
Tim Allen committed
619 620 621 622 623 624 625 626 627 628 629 630 631
        E_CASE( KaxVideoColourSpace, colourspace )
        {
            if ( colourspace.ValidateSize() )
            {
                char clrspc[5];

                vars.tk->fmt.i_codec = GetFOURCC( colourspace.GetBuffer() );

                vlc_fourcc_to_char( vars.tk->fmt.i_codec, clrspc );
                clrspc[4]  = '\0';
                debug( vars, "Colour Space=%s", clrspc );
            }
        }
632
        E_CASE( KaxTrackAudio, tka ) {
633
            debug( vars, "Track Audio");
634 635 636
            if (vars.tk->fmt.i_cat != AUDIO_ES ) {
                msg_Err( vars.p_demuxer, "Audio elements not allowed for this track" );
            } else {
637 638 639
            vars.level += 1;
            dispatcher.iterate( tka.begin(), tka.end(), Payload( vars ));
            vars.level -= 1;
640
            }
641
        }
642
        E_CASE( KaxAudioSamplingFreq, afreq )
643
        {
644 645 646 647
            float const value = static_cast<float>( afreq );

            vars.tk->i_original_rate  = value;
            vars.tk->fmt.audio.i_rate = value;
648

649
            debug( vars, "afreq=%d", vars.tk->fmt.audio.i_rate ) ;
650
        }
651 652
        E_CASE( KaxAudioOutputSamplingFreq, afreq )
        {
653 654
            vars.tk->fmt.audio.i_rate = static_cast<float>( afreq );
            debug( vars, "aoutfreq=%d", vars.tk->fmt.audio.i_rate ) ;
655 656 657 658
        }
        E_CASE( KaxAudioChannels, achan )
        {
            vars.tk->fmt.audio.i_channels = static_cast<uint8>( achan );
659
            debug( vars, "achan=%u", vars.tk->fmt.audio.i_channels );
660 661 662 663
        }
        E_CASE( KaxAudioBitDepth, abits )
        {
            vars.tk->fmt.audio.i_bitspersample = static_cast<uint8>( abits );
664
            debug( vars, "abits=%u", vars.tk->fmt.audio.i_bitspersample);
665 666 667 668 669
        }
        E_CASE ( EbmlVoid, ) {
          VLC_UNUSED( vars );
        }
        E_CASE_DEFAULT(element) {
670
            debug( vars, "Unknown (%s)", typeid(element).name() );
671 672 673 674 675
        }
    };

    MetaDataHandlers::Dispatcher().iterate ( m->begin(), m->end(), MetaDataHandlers::Payload( metadata_payload ) );

676 677 678
    if( track.i_number == 0 )
    {
        msg_Warn( &sys.demuxer, "Missing KaxTrackNumber, discarding track!" );
679 680
        es_format_Clean( &track.fmt );
        free(track.p_extra_data);
681 682
        return;
    }
683

684
    if ( bSupported )
685
    {
686
#ifdef HAVE_ZLIB_H
687 688 689 690
        if( track.i_compression_type == MATROSKA_COMPRESSION_ZLIB &&
            track.i_encoding_scope & MATROSKA_ENCODING_SCOPE_PRIVATE &&
            track.i_extra_data && track.p_extra_data &&
            zlib_decompress_extra( &sys.demuxer, &track ) )
691
            // zlib_decompress_extra will clean the track itself
692 693
            return;
#endif
694
        if( TrackInit( &track ) )
695
        {
696
            msg_Err(&sys.demuxer, "Couldn't init track %u", track.i_number );
697
            es_format_Clean( &track.fmt );
698
            free(track.p_extra_data);
699 700
            return;
        }
701

702
        tracks.insert( std::make_pair( track.i_number, track ) ); // TODO: add warning if two tracks have the same key
703 704 705
    }
    else
    {
706
        msg_Err( &sys.demuxer, "Track Entry %u not supported", track.i_number );
707
        es_format_Clean( &track.fmt );
708
        free(track.p_extra_data);
709 710 711
    }
}

712 713 714 715
/*****************************************************************************
 * ParseTracks:
 *****************************************************************************/
void matroska_segment_c::ParseTracks( KaxTracks *tracks )
716
{
717 718 719 720
    EbmlElement *el;
    int i_upper_level = 0;

    /* Master elements */
721
    if( unlikely( tracks->IsFiniteSize() && tracks->GetSize() >= SIZE_MAX ) )
722 723 724 725
    {
        msg_Err( &sys.demuxer, "Track too big, aborting" );
        return;
    }
726 727 728 729 730 731 732 733 734
    try
    {
        tracks->Read( es, EBML_CONTEXT(tracks), i_upper_level, el, true );
    }
    catch(...)
    {
        msg_Err( &sys.demuxer, "Couldn't read tracks" );
        return;
    }
735

736 737 738 739 740 741 742 743 744
    struct Capture {
      matroska_segment_c * obj;
      demux_t            * p_demuxer;

    } payload = {
      this, &sys.demuxer
    };

    MKV_SWITCH_CREATE( EbmlTypeDispatcher, TrackHandlers, struct Capture )
745
    {
746
        MKV_SWITCH_INIT();
747

748 749
        E_CASE( KaxTrackEntry, track_number ) {
            vars.obj->ParseTrackEntry( &track_number );
750
        }
751 752
        E_CASE( EbmlVoid, ) {
            VLC_UNUSED( vars );
753
        }
754
        E_CASE_DEFAULT(element) {
755
            MkvTree( *vars.p_demuxer, 2, "Unknown (%s)", typeid(element).name() );
756 757 758 759 760
        }
    };

    TrackHandlers::Dispatcher().iterate(
      tracks->begin(), tracks->end(), TrackHandlers::Payload( payload ) );
761 762
}

763 764 765 766
/*****************************************************************************
 * ParseInfo:
 *****************************************************************************/
void matroska_segment_c::ParseInfo( KaxInfo *info )
767
{
768 769 770 771 772 773
    EbmlElement *el;
    EbmlMaster  *m;
    int i_upper_level = 0;

    /* Master elements */
    m = static_cast<EbmlMaster *>(info);
774
    if( unlikely( m->IsFiniteSize() && m->GetSize() >= SIZE_MAX ) )
775 776 777 778
    {
        msg_Err( &sys.demuxer, "Info too big, aborting" );
        return;
    }
779 780 781 782 783 784 785 786
    try
    {
        m->Read( es, EBML_CONTEXT(info), i_upper_level, el, true );
    }
    catch(...)
    {
        msg_Err( &sys.demuxer, "Couldn't read info" );
        return;
787
    }
788

789 790 791 792 793 794 795 796 797 798
    struct InfoHandlerPayload {
        demux_t            * p_demuxer;
        matroska_segment_c * obj;
        EbmlElement       *&  el;
        EbmlMaster        *&   m;
        int& i_upper_level;

    } captures = { &sys.demuxer, this, el, m, i_upper_level };

    MKV_SWITCH_CREATE(EbmlTypeDispatcher, InfoHandlers, InfoHandlerPayload)
799
    {
800
        MKV_SWITCH_INIT();
801

802 803 804 805 806 807
        static void debug (InfoHandlerPayload& vars, char const * fmt, ...)
        {
            va_list args; va_start( args, fmt );
            MkvTree_va( *vars.p_demuxer, 2, fmt, args);
            va_end( args );
        }
808
        E_CASE( KaxSegmentUID, uid )
809
        {
810
            if ( vars.obj->p_segment_uid == NULL )
811
            {
812
                vars.obj->p_segment_uid = new KaxSegmentUID( uid );
813 814
            }
            debug( vars, "UID=%d", *reinterpret_cast<uint32*>( vars.obj->p_segment_uid->GetBuffer() ) );
815
        }
816
        E_CASE( KaxPrevUID, uid )
817
        {
818
            if ( vars.obj->p_prev_segment_uid == NULL )
819
            {
820 821
                vars.o