Coverage Report

Created: 2025-08-29 07:30

/src/vlc/modules/demux/mkv/matroska_segment_parse.cpp
Line
Count
Source (jump to first uncovered line)
1
/*****************************************************************************
2
 * matroska_segment_parse.cpp : matroska demuxer
3
 *****************************************************************************
4
 * Copyright (C) 2003-2010 VLC authors and VideoLAN
5
 *
6
 * Authors: Laurent Aimar <fenrir@via.ecp.fr>
7
 *          Steve Lhomme <steve.lhomme@free.fr>
8
 *
9
 * This program is free software; you can redistribute it and/or modify it
10
 * under the terms of the GNU Lesser General Public License as published by
11
 * the Free Software Foundation; either version 2.1 of the License, or
12
 * (at your option) any later version.
13
 *
14
 * This program is distributed in the hope that it will be useful,
15
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
 * GNU Lesser General Public License for more details.
18
 *
19
 * You should have received a copy of the GNU Lesser General Public License
20
 * along with this program; if not, write to the Free Software Foundation,
21
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22
 *****************************************************************************/
23
#include "mkv.hpp"
24
#include "matroska_segment.hpp"
25
#include "chapters.hpp"
26
#include "demux.hpp"
27
#include "Ebml_parser.hpp"
28
#include "Ebml_dispatcher.hpp"
29
#include "string_dispatcher.hpp"
30
#include "util.hpp"
31
#include "chapter_command_script.hpp"
32
33
extern "C" {
34
#include "../vobsub.h"
35
#include "../xiph.h"
36
#include "../windows_audio_commons.h"
37
#include "../mp4/libmp4.h"
38
}
39
40
#include "vlc_colors.h"
41
42
#include <vlc_codecs.h>
43
#include <stdexcept>
44
#include <limits>
45
#include <algorithm>
46
47
namespace mkv {
48
49
/* GetFourCC helper */
50
4
#define GetFOURCC( p )  __GetFOURCC( (uint8_t*)p )
51
static vlc_fourcc_t __GetFOURCC( uint8_t *p )
52
4
{
53
4
    return VLC_FOURCC( p[0], p[1], p[2], p[3] );
54
4
}
55
56
static inline void fill_extra_data_alac( mkv_track_t *p_tk )
57
0
{
58
0
    if( p_tk->i_extra_data <= 0 ) return;
59
0
    p_tk->fmt.p_extra = malloc( p_tk->i_extra_data + 12 );
60
0
    if( unlikely( !p_tk->fmt.p_extra ) ) return;
61
0
    p_tk->fmt.i_extra = p_tk->i_extra_data + 12;
62
0
    uint8_t *p_extra = static_cast<uint8_t*>( p_tk->fmt.p_extra );
63
    /* 12 bytes + "ALAC Specific Info (24 bytes) (required)" from
64
       https://github.com/macosforge/alac/blob/master/ALACMagicCookieDescription.txt */
65
0
    SetDWBE( p_extra, p_tk->fmt.i_extra );
66
0
    memcpy( p_extra + 4, "alac", 4 );
67
0
    SetDWBE( p_extra + 8, p_tk->i_extra_data );
68
0
    memcpy( p_extra + 12, p_tk->p_extra_data, p_tk->i_extra_data );
69
0
}
70
71
static inline void fill_extra_data( mkv_track_t *p_tk, unsigned int offset )
72
18
{
73
18
    if(p_tk->i_extra_data <= offset) return;
74
18
    p_tk->fmt.i_extra = p_tk->i_extra_data - offset;
75
18
    p_tk->fmt.p_extra = xmalloc( p_tk->fmt.i_extra );
76
18
    if(!p_tk->fmt.p_extra) { p_tk->fmt.i_extra = 0; return; };
77
18
    memcpy( p_tk->fmt.p_extra, p_tk->p_extra_data + offset, p_tk->fmt.i_extra );
78
18
}
79
80
/*****************************************************************************
81
 * Some functions to manipulate memory
82
 *****************************************************************************/
83
static inline char * ToUTF8( const UTFstring &u )
84
33
{
85
33
    return strdup( u.GetUTF8().c_str() );
86
33
}
87
88
/*****************************************************************************
89
 * ParseSeekHead:
90
 *****************************************************************************/
91
void matroska_segment_c::ParseSeekHead( KaxSeekHead *seekhead )
92
15
{
93
15
    EbmlElement *l;
94
95
15
    i_seekhead_count++;
96
97
15
    if( !sys.b_seekable )
98
0
        return;
99
100
15
    EbmlParser eparser ( &es, seekhead, &sys.demuxer );
101
102
79
    while( ( l = eparser.Get() ) != NULL )
103
64
    {
104
64
        if( MKV_IS_ID( l, KaxSeek ) )
105
60
        {
106
60
            EbmlId id = EBML_ID(EbmlVoid);
107
60
            int64_t i_pos = -1;
108
109
#ifdef MKV_DEBUG
110
            msg_Dbg( &sys.demuxer, "|   |   + Seek" );
111
#endif
112
60
            eparser.Down();
113
60
            try
114
60
            {
115
208
                while( ( l = eparser.Get() ) != NULL )
116
148
                {
117
148
                    if( unlikely( !l->ValidateSize() ) )
118
0
                    {
119
0
                        msg_Err( &sys.demuxer,"%s too big... skipping it",  EBML_NAME(l) );
120
0
                        continue;
121
0
                    }
122
148
                    if( MKV_IS_ID( l, KaxSeekID ) )
123
60
                    {
124
60
                        KaxSeekID &sid = *static_cast<KaxSeekID*>( l );
125
60
                        sid.ReadData( es.I_O() );
126
60
                        id = EbmlId( sid.GetBuffer(), sid.GetSize() );
127
60
                    }
128
88
                    else if( MKV_IS_ID( l, KaxSeekPosition ) )
129
60
                    {
130
60
                        KaxSeekPosition &spos = *static_cast<KaxSeekPosition*>( l );
131
60
                        spos.ReadData( es.I_O() );
132
60
                        i_pos = (int64_t)segment->GetGlobalPosition( static_cast<uint64_t>( spos ) );
133
60
                    }
134
28
                    else if ( !MKV_IS_ID( l, EbmlVoid ) && !MKV_IS_ID( l, EbmlCrc32 ))
135
0
                    {
136
                        /* Many mkvmerge files hit this case. It seems to be a broken SeekHead */
137
0
                        msg_Dbg( &sys.demuxer, "|   |   + Unknown (%s)", EBML_NAME(l) );
138
0
                    }
139
148
                }
140
60
            }
141
60
            catch(...)
142
60
            {
143
0
                msg_Err( &sys.demuxer,"Error while reading %s",  EBML_NAME(l) );
144
0
            }
145
60
            eparser.Up();
146
147
60
            if( i_pos >= 0 )
148
60
            {
149
60
                if( id == EBML_ID(KaxCluster) )
150
6
                {
151
6
                    _seeker.add_cluster_position( i_pos );
152
6
                }
153
54
                else if( id == EBML_ID(KaxCues) )
154
14
                {
155
14
                    msg_Dbg( &sys.demuxer, "|   - cues at %" PRId64, i_pos );
156
14
                    LoadSeekHeadItem( EBML_INFO(KaxCues), i_pos );
157
14
                }
158
40
                else if( id == EBML_ID(KaxInfo) )
159
15
                {
160
15
                    msg_Dbg( &sys.demuxer, "|   - info at %" PRId64, i_pos );
161
15
                    LoadSeekHeadItem( EBML_INFO(KaxInfo), i_pos );
162
15
                }
163
25
                else if( id == EBML_ID(KaxChapters) )
164
0
                {
165
0
                    msg_Dbg( &sys.demuxer, "|   - chapters at %" PRId64, i_pos );
166
0
                    LoadSeekHeadItem( EBML_INFO(KaxChapters), i_pos );
167
0
                }
168
25
                else if( id == EBML_ID(KaxTags) )
169
10
                {
170
10
                    msg_Dbg( &sys.demuxer, "|   - tags at %" PRId64, i_pos );
171
10
                    LoadSeekHeadItem( EBML_INFO(KaxTags), i_pos );
172
10
                }
173
15
                else if( id == EBML_ID(KaxSeekHead) )
174
0
                {
175
0
                    msg_Dbg( &sys.demuxer, "|   - chained seekhead at %" PRId64, i_pos );
176
0
                    LoadSeekHeadItem( EBML_INFO(KaxSeekHead), i_pos );
177
0
                }
178
15
                else if( id == EBML_ID(KaxTracks) )
179
15
                {
180
15
                    msg_Dbg( &sys.demuxer, "|   - tracks at %" PRId64, i_pos );
181
15
                    LoadSeekHeadItem( EBML_INFO(KaxTracks), i_pos );
182
15
                }
183
0
                else if( id == EBML_ID(KaxAttachments) )
184
0
                {
185
0
                    msg_Dbg( &sys.demuxer, "|   - attachments at %" PRId64, i_pos );
186
0
                    LoadSeekHeadItem( EBML_INFO(KaxAttachments), i_pos );
187
0
                }
188
#ifdef MKV_DEBUG
189
                else if( id != EBML_ID(KaxCluster) && id != EBML_ID(EbmlVoid) &&
190
                         id != EBML_ID(EbmlCrc32))
191
                    msg_Dbg( &sys.demuxer, "|   - unknown seekhead reference at %" PRId64, i_pos );
192
#endif
193
60
            }
194
60
        }
195
4
        else if ( !MKV_IS_ID( l, EbmlVoid ) && !MKV_IS_ID( l, EbmlCrc32 ))
196
0
            msg_Dbg( &sys.demuxer, "|   |   + ParseSeekHead Unknown (%s)", EBML_NAME(l) );
197
64
    }
198
15
}
199
200
201
/*****************************************************************************
202
 * ParseTrackEntry:
203
 *****************************************************************************/
204
105
#define ONLY_FMT(t) if(vars.tk->fmt.i_cat != t ## _ES) return
205
void matroska_segment_c::ParseTrackEntry( const KaxTrackEntry *m )
206
35
{
207
35
    bool bSupported = true;
208
209
35
    uint8_t ttype;
210
35
    try {
211
35
        KaxTrackType & pTrackType = GetMandatoryChild<KaxTrackType>(*m);
212
35
        ttype = pTrackType;
213
35
    } catch (const MissingMandatory & err) {
214
0
        msg_Dbg( &sys.demuxer, "%s", err.what());
215
0
        ttype = 0;
216
0
    }
217
218
35
    enum es_format_category_e es_cat;
219
35
    switch( ttype )
220
35
    {
221
11
        case track_audio:
222
11
            es_cat = AUDIO_ES;
223
11
            break;
224
16
        case track_video:
225
16
            es_cat = VIDEO_ES;
226
16
            break;
227
8
        case track_subtitle:
228
8
        case track_buttons:
229
8
            es_cat = SPU_ES;
230
8
            break;
231
0
        default:
232
0
            es_cat = UNKNOWN_ES;
233
0
            break;
234
35
    }
235
236
    /* Init the track */
237
35
    mkv_track_t *p_track = new mkv_track_t(es_cat);
238
239
35
    MkvTree( sys.demuxer, 2, "Track Entry" );
240
241
35
    struct MetaDataCapture {
242
35
      matroska_segment_c * obj;
243
35
      mkv_track_t        * tk;
244
35
      demux_t            * p_demuxer;
245
35
      bool&                bSupported;
246
35
      int                  level;
247
35
      struct {
248
35
        unsigned int i_crop_right;
249
35
        unsigned int i_crop_left;
250
35
        unsigned int i_crop_top;
251
35
        unsigned int i_crop_bottom;
252
35
        unsigned int i_display_unit;
253
35
        unsigned int i_display_width;
254
35
        unsigned int i_display_height;
255
256
35
        unsigned int chroma_sit_vertical;
257
35
        unsigned int chroma_sit_horizontal;
258
35
      } track_video_info;
259
260
35
      struct {
261
35
          float yaw;
262
35
          float pitch;
263
35
          float roll;
264
35
      } pose;
265
266
35
    } metadata_payload = {
267
35
      this, p_track, &sys.demuxer, bSupported, 3, { }, { }
268
35
    };
269
270
35
    MKV_SWITCH_CREATE( EbmlTypeDispatcher, MetaDataHandlers, MetaDataCapture )
271
35
    {
272
35
        MKV_SWITCH_INIT();
273
274
35
        static void debug (MetaDataCapture const& vars, char const * fmt, ...)
275
360
        {
276
360
            va_list args; va_start( args, fmt );
277
360
            MkvTree_va( *vars.p_demuxer, vars.level, fmt, args);
278
360
            va_end( args );
279
360
        }
280
35
        E_CASE( KaxTrackNumber, tnum )
281
35
        {
282
35
            vars.tk->i_number = static_cast<uint32_t>( tnum );
283
35
            debug( vars, "Track Number=%u", vars.tk->i_number );
284
35
        }
285
35
        E_CASE( KaxTrackUID, tuid )
286
35
        {
287
35
            debug( vars, "Track UID=%x", static_cast<uint32_t>( tuid ) );
288
35
        }
289
35
        E_CASE( KaxTrackType, ttype )
290
35
        {
291
35
            const char *psz_type;
292
293
35
            switch( static_cast<uint8_t>( ttype ) )
294
35
            {
295
11
                case track_audio:
296
11
                    psz_type = "audio";
297
11
                    break;
298
16
                case track_video:
299
16
                    psz_type = "video";
300
16
                    break;
301
8
                case track_subtitle:
302
8
                    psz_type = "subtitle";
303
8
                    break;
304
0
                case track_buttons:
305
0
                    psz_type = "buttons";
306
0
                    break;
307
0
                default:
308
0
                    psz_type = "unknown";
309
0
                    break;
310
35
            }
311
312
35
            debug( vars, "Track Type=%s", psz_type ) ;
313
35
        }
314
        E_CASE( KaxTrackFlagEnabled, fenb ) // UNUSED
315
35
        {
316
0
            vars.tk->b_enabled = static_cast<uint32_t>( fenb );
317
0
            debug( vars, "Track Enabled=%u", vars.tk->b_enabled );
318
0
        }
319
35
        E_CASE( KaxTrackFlagDefault, fdef )
320
35
        {
321
13
            vars.tk->b_default = static_cast<uint32_t>( fdef );
322
13
            debug( vars, "Track Default=%u", vars.tk->b_default );
323
13
        }
324
        E_CASE( KaxTrackFlagForced, ffor ) // UNUSED
325
35
        {
326
0
            vars.tk->b_forced = static_cast<uint32_t>( ffor );
327
328
0
            debug( vars, "Track Forced=%u", vars.tk->b_forced );
329
0
        }
330
        E_CASE( KaxTrackFlagLacing, lac ) // UNUSED
331
35
        {
332
24
            debug( vars, "Track Lacing=%d", static_cast<uint32_t>( lac ) ) ;
333
24
        }
334
        E_CASE( KaxTrackMinCache, cmin ) // UNUSED
335
35
        {
336
7
            debug( vars, "Track MinCache=%d", static_cast<uint32_t>( cmin ) ) ;
337
7
        }
338
        E_CASE( KaxTrackMaxCache, cmax ) // UNUSED
339
35
        {
340
0
            debug( vars, "Track MaxCache=%d", static_cast<uint32_t>( cmax ) ) ;
341
0
        }
342
35
        E_CASE( KaxTrackDefaultDuration, defd )
343
35
        {
344
16
            vars.tk->i_default_duration = VLC_TICK_FROM_NS(static_cast<uint64_t>(defd));
345
16
            debug( vars, "Track Default Duration=%" PRId64, vars.tk->i_default_duration );
346
16
        }
347
35
        E_CASE( KaxTrackTimestampScale, ttcs )
348
35
        {
349
0
            vars.tk->f_timecodescale = static_cast<float>( ttcs );
350
0
            if ( vars.tk->f_timecodescale <= 0 ) vars.tk->f_timecodescale = 1.0;
351
0
            debug( vars, "Track TimeCodeScale=%f", vars.tk->f_timecodescale ) ;
352
0
        }
353
        E_CASE( KaxMaxBlockAdditionID, mbl ) // UNUSED
354
35
        {
355
5
            debug( vars, "Track Max BlockAdditionID=%d", static_cast<uint32_t>( mbl ) ) ;
356
5
        }
357
35
        E_CASE( KaxTrackName, tname )
358
35
        {
359
1
            vars.tk->fmt.psz_description = ToUTF8( UTFstring( tname ) );
360
1
            debug( vars, "Track Name=%s", vars.tk->fmt.psz_description ? vars.tk->fmt.psz_description : "(null)" );
361
1
        }
362
35
        E_CASE( KaxTrackLanguage, lang )
363
35
        {
364
27
            free( vars.tk->fmt.psz_language );
365
27
            const std::string slang ( lang );
366
27
            size_t pos = slang.find_first_of( '-' );
367
27
            vars.tk->fmt.psz_language = pos != std::string::npos ? strndup( slang.c_str (), pos ) : strdup( slang.c_str() );
368
27
            debug( vars, "Track Language=`%s'", vars.tk->fmt.psz_language ? vars.tk->fmt.psz_language : "(null)" );
369
27
        }
370
35
        E_CASE( KaxCodecID, codecid )
371
35
        {
372
35
            vars.tk->codec = std::string( codecid );
373
35
            debug( vars, "Track CodecId=%s", std::string( codecid ).c_str() ) ;
374
35
        }
375
35
        E_CASE( KaxCodecPrivate, cpriv )
376
35
        {
377
22
            vars.tk->i_extra_data = cpriv.GetSize();
378
22
            if( vars.tk->i_extra_data > 0 )
379
22
            {
380
22
                vars.tk->p_extra_data = static_cast<uint8_t*>( malloc( vars.tk->i_extra_data ) );
381
382
22
                if( likely( vars.tk->p_extra_data ) )
383
22
                    memcpy( vars.tk->p_extra_data, cpriv.GetBuffer(),
384
22
                            vars.tk->i_extra_data );
385
22
            }
386
22
            debug( vars, "Track CodecPrivate size=%" PRId64, cpriv.GetSize() );
387
22
        }
388
35
        E_CASE( KaxCodecName, cname )
389
35
        {
390
0
            vars.tk->str_codec_name = static_cast<UTFstring const&>( cname ).GetUTF8();
391
0
            debug( vars, "Track Codec Name=%s", vars.tk->str_codec_name.c_str() ) ;
392
0
        }
393
        //AttachmentLink
394
        E_CASE( KaxCodecDecodeAll, cdall ) // UNUSED
395
35
        {
396
0
            debug( vars, "Track Codec Decode All=%u", static_cast<uint8_t>( cdall ) ) ;
397
0
        }
398
        E_CASE( KaxTrackOverlay, tovr ) // UNUSED
399
35
        {
400
0
            debug( vars, "Track Overlay=%u", static_cast<uint32_t>( tovr ) ) ;
401
0
        }
402
35
#if LIBMATROSKA_VERSION >= 0x010401
403
35
        E_CASE( KaxCodecDelay, codecdelay )
404
35
        {
405
0
            vars.tk->i_codec_delay = VLC_TICK_FROM_NS(static_cast<uint64_t>( codecdelay ));
406
0
            msg_Dbg( vars.p_demuxer, "|   |   |   + Track Codec Delay =%" PRIu64,
407
0
                     vars.tk->i_codec_delay );
408
0
        }
409
35
        E_CASE( KaxSeekPreRoll, spr )
410
35
        {
411
0
            vars.tk->i_seek_preroll = VLC_TICK_FROM_NS(static_cast<uint64_t>( spr ));
412
0
            debug( vars, "Track Seek Preroll =%" PRIu64, vars.tk->i_seek_preroll );
413
0
        }
414
35
#endif
415
35
        E_CASE( KaxContentEncodings, cencs )
416
35
        {
417
0
            debug( vars, "Content Encodings" );
418
419
0
            if ( cencs.ListSize () > 1 )
420
0
            {
421
0
                msg_Err( vars.p_demuxer, "Multiple Compression method not supported" );
422
0
                vars.bSupported = false;
423
0
            }
424
425
0
            vars.level += 1;
426
0
            dispatcher.iterate( cencs.begin(), cencs.end(), &vars );
427
0
            vars.level -= 1;
428
0
        }
429
35
        E_CASE( KaxContentEncoding, cenc )
430
35
        {
431
0
            debug( vars, "Content Encoding" );
432
433
0
            vars.level += 1;
434
0
            dispatcher.iterate( cenc.begin(), cenc.end(), &vars );
435
0
            vars.level -= 1;
436
0
        }
437
35
        E_CASE( KaxContentEncodingOrder, encord )
438
35
        {
439
0
            debug( vars, "Order: %i", static_cast<uint32_t>( encord ) );
440
0
        }
441
35
        E_CASE( KaxContentEncodingScope, encscope )
442
35
        {
443
0
            vars.tk->i_encoding_scope = static_cast<uint32_t>( encscope );
444
0
            debug( vars, "Scope: %i", vars.tk->i_encoding_scope );
445
0
        }
446
35
        E_CASE( KaxContentEncodingType, enctype )
447
35
        {
448
0
            debug( vars, "Type: %i", static_cast<uint32_t>( enctype ) );
449
0
        }
450
35
        E_CASE( KaxContentCompression, compr )
451
35
        {
452
0
            debug( vars, "Content Compression" );
453
            //Default compression type is 0 (Zlib)
454
0
            vars.tk->i_compression_type = MATROSKA_COMPRESSION_ZLIB;
455
456
0
            vars.level += 1;
457
0
            dispatcher.iterate( compr.begin(), compr.end(), &vars );
458
0
            vars.level -= 1;
459
0
        }
460
35
        E_CASE( KaxContentCompAlgo, compalg )
461
35
        {
462
0
            vars.tk->i_compression_type = static_cast<uint32_t>( compalg );
463
0
            debug( vars, "Compression Algorithm: %i", vars.tk->i_compression_type );
464
0
            if ( ( vars.tk->i_compression_type != MATROSKA_COMPRESSION_ZLIB ) &&
465
0
                 ( vars.tk->i_compression_type != MATROSKA_COMPRESSION_HEADER ) )
466
0
            {
467
0
                msg_Err( vars.p_demuxer, "Track Compression method %d not supported", vars.tk->i_compression_type );
468
0
                vars.bSupported = false;
469
0
            }
470
0
        }
471
35
        E_CASE( KaxContentCompSettings, kccs )
472
35
        {
473
0
            vars.tk->p_compression_data = new KaxContentCompSettings( kccs );
474
0
        }
475
35
        E_CASE( KaxTrackVideo, tkv )
476
35
        {
477
16
            ONLY_FMT(VIDEO);
478
16
            debug( vars, "Track Video");
479
480
16
            mkv_track_t *tk = vars.tk;
481
482
16
            tk->f_fps = 0.0;
483
484
16
            if( tk->i_default_duration > 1000 ) /* Broken ffmpeg mux info when non set fps */
485
11
            {
486
11
                tk->fmt.video.i_frame_rate_base = static_cast<unsigned>( tk->i_default_duration );
487
11
                tk->fmt.video.i_frame_rate = 1000000;
488
11
            }
489
490
16
            vars.level += 1;
491
16
            dispatcher.iterate (tkv.begin (), tkv.end (), &vars );
492
16
            vars.level -= 1;
493
494
16
            unsigned int i_crop_top    = vars.track_video_info.i_crop_top;
495
16
            unsigned int i_crop_right  = vars.track_video_info.i_crop_right;
496
16
            unsigned int i_crop_bottom = vars.track_video_info.i_crop_bottom;
497
16
            unsigned int i_crop_left   = vars.track_video_info.i_crop_left;
498
499
16
            unsigned int i_display_unit   = vars.track_video_info.i_display_unit;
500
16
            unsigned int i_display_width  = vars.track_video_info.i_display_width;
501
16
            unsigned int i_display_height = vars.track_video_info.i_display_height;
502
503
16
            if (vars.track_video_info.chroma_sit_vertical || vars.track_video_info.chroma_sit_horizontal)
504
0
            {
505
0
                switch (vars.track_video_info.chroma_sit_vertical)
506
0
                {
507
0
                case 0: // unspecified
508
0
                case 2: // center
509
0
                    if (vars.track_video_info.chroma_sit_horizontal == 1) // left
510
0
                        tk->fmt.video.chroma_location = CHROMA_LOCATION_LEFT;
511
0
                    else if (vars.track_video_info.chroma_sit_horizontal == 2) // half
512
0
                        tk->fmt.video.chroma_location = CHROMA_LOCATION_CENTER;
513
0
                    else
514
0
                        debug( vars, "unsupported chroma Siting %u/%u",
515
0
                               vars.track_video_info.chroma_sit_horizontal,
516
0
                               vars.track_video_info.chroma_sit_vertical);
517
0
                    break;
518
0
                case 1: // top
519
0
                    if (vars.track_video_info.chroma_sit_horizontal == 1) // left
520
0
                        tk->fmt.video.chroma_location = CHROMA_LOCATION_TOP_LEFT;
521
0
                    else if (vars.track_video_info.chroma_sit_horizontal == 2) // half
522
0
                        tk->fmt.video.chroma_location = CHROMA_LOCATION_TOP_CENTER;
523
0
                    else
524
0
                        debug( vars, "unsupported chroma Siting %u/%u",
525
0
                               vars.track_video_info.chroma_sit_horizontal,
526
0
                               vars.track_video_info.chroma_sit_vertical);
527
0
                    break;
528
0
                }
529
0
            }
530
531
16
            unsigned int h_crop;
532
16
            if (add_overflow(i_crop_left, i_crop_right, &h_crop))
533
0
            {
534
0
                debug( vars, "invalid horizontal crop %u+%u",
535
0
                              i_crop_left, i_crop_right );
536
0
                i_crop_left = i_crop_right = 0;
537
0
            }
538
16
            else if (unlikely(h_crop >= tk->fmt.video.i_width))
539
0
            {
540
0
                debug( vars, "Horizontal crop (left=%u, right=%u) "
541
0
                             "greater than the picture width (%u)",
542
0
                              i_crop_left, i_crop_right, tk->fmt.video.i_width );
543
0
                i_crop_left = i_crop_right = 0;
544
0
            }
545
546
16
            unsigned int v_crop;
547
16
            if (add_overflow(i_crop_top, i_crop_bottom, &v_crop))
548
0
            {
549
0
                debug( vars, "invalid vertical crop %u+%u",
550
0
                              i_crop_top, i_crop_bottom);
551
0
                i_crop_top = i_crop_bottom = 0;
552
0
            }
553
16
            if (unlikely(v_crop >= tk->fmt.video.i_height))
554
0
            {
555
0
                debug( vars, "Vertical crop (top=%u, bottom=%u) "
556
0
                             "greater than the picture height (%u)",
557
0
                              i_crop_top, i_crop_bottom, tk->fmt.video.i_height );
558
0
                i_crop_top = i_crop_bottom = 0;
559
0
            }
560
561
16
            tk->fmt.video.i_x_offset      = i_crop_left;
562
16
            tk->fmt.video.i_y_offset      = i_crop_top;
563
16
            tk->fmt.video.i_visible_width = tk->fmt.video.i_width -
564
16
                                            (i_crop_left + i_crop_right);
565
16
            tk->fmt.video.i_visible_height = tk->fmt.video.i_height -
566
16
                                            (i_crop_top + i_crop_bottom);
567
568
16
            if (i_display_unit == 0 && i_display_width == 0)
569
10
                i_display_width = tk->fmt.video.i_width;
570
16
            if (i_display_unit == 0 && i_display_height == 0)
571
11
                i_display_height = tk->fmt.video.i_height;
572
573
16
            if (i_display_height && i_display_width)
574
16
            {
575
16
                switch (i_display_unit)
576
16
                {
577
16
                    case 0: // pixels
578
16
                    case 1: // centimeters
579
16
                    case 2: // inches
580
16
                        vlc_ureduce( &tk->fmt.video.i_sar_num, &tk->fmt.video.i_sar_den,
581
16
                                     i_display_width * tk->fmt.video.i_visible_height,
582
16
                                     i_display_height * tk->fmt.video.i_visible_width, 0);
583
16
                        break;
584
0
                    case 3: // display aspect ratio
585
0
                        vlc_ureduce( &tk->fmt.video.i_sar_num, &tk->fmt.video.i_sar_den,
586
0
                                     i_display_height * tk->fmt.video.i_visible_width,
587
0
                                     i_display_width * tk->fmt.video.i_visible_height, 0);
588
0
                        break;
589
16
                }
590
16
            }
591
16
        }
592
35
#if LIBMATROSKA_VERSION >= 0x010400
593
35
        E_CASE( KaxVideoAlphaMode, mode )
594
35
        {
595
5
            ONLY_FMT(VIDEO);
596
5
            debug( vars, "Track Video Alpha Mode %u", static_cast<uint8_t>( mode ) ) ;
597
5
            vars.tk->b_has_alpha = static_cast<uint8_t>( mode ) == 1;
598
5
        }
599
35
#endif
600
35
#if LIBMATROSKA_VERSION >= 0x010406
601
35
        E_CASE( KaxVideoProjection, proj )
602
35
        {
603
0
            ONLY_FMT(VIDEO);
604
0
            debug( vars, "Track Video Projection" ) ;
605
606
0
            vars.level += 1;
607
0
            dispatcher.iterate (proj.begin (), proj.end (), &vars );
608
0
            vars.level -= 1;
609
0
        }
610
35
        E_CASE( KaxVideoProjectionType, fint )
611
35
        {
612
0
            ONLY_FMT(VIDEO);
613
0
            switch (static_cast<uint8_t>( fint ))
614
0
            {
615
0
            case 0:
616
0
                vars.tk->fmt.video.projection_mode = PROJECTION_MODE_RECTANGULAR;
617
0
                break;
618
0
            case 1:
619
0
                vars.tk->fmt.video.projection_mode = PROJECTION_MODE_EQUIRECTANGULAR;
620
0
                break;
621
0
            case 2:
622
0
                vars.tk->fmt.video.projection_mode = PROJECTION_MODE_CUBEMAP_LAYOUT_STANDARD;
623
0
                break;
624
0
            default:
625
0
                debug( vars, "Track Video Projection %u not supported", static_cast<uint8_t>( fint ) ) ;
626
0
                break;
627
0
            }
628
0
        }
629
35
        E_CASE( KaxVideoProjectionPoseYaw, pose )
630
35
        {
631
0
            ONLY_FMT(VIDEO);
632
0
            vars.pose.yaw = static_cast<float>( pose );
633
0
        }
634
35
        E_CASE( KaxVideoProjectionPosePitch, pose )
635
35
        {
636
0
            ONLY_FMT(VIDEO);
637
0
            vars.pose.pitch = static_cast<float>( pose );
638
0
        }
639
35
        E_CASE( KaxVideoProjectionPoseRoll, pose )
640
35
        {
641
0
            ONLY_FMT(VIDEO);
642
0
            vars.pose.roll = static_cast<float>( pose );
643
0
        }
644
35
#endif
645
        E_CASE( KaxVideoFlagInterlaced, fint ) // UNUSED
646
35
        {
647
4
            ONLY_FMT(VIDEO);
648
4
            debug( vars, "Track Video Interlaced=%u", static_cast<uint8_t>( fint ) ) ;
649
4
        }
650
        E_CASE( KaxVideoStereoMode, stereo ) // UNUSED
651
35
        {
652
0
            ONLY_FMT(VIDEO);
653
0
            vars.tk->fmt.video.b_multiview_right_eye_first = false;
654
0
            switch (static_cast<uint8_t>( stereo ))
655
0
            {
656
0
            case 0: vars.tk->fmt.video.multiview_mode = MULTIVIEW_2D;         break;
657
0
            case 1: vars.tk->fmt.video.multiview_mode = MULTIVIEW_STEREO_SBS; break;
658
0
            case 2: vars.tk->fmt.video.multiview_mode = MULTIVIEW_STEREO_TB;  break;
659
0
            case 3: vars.tk->fmt.video.multiview_mode = MULTIVIEW_STEREO_TB;
660
0
                    vars.tk->fmt.video.b_multiview_right_eye_first = true;    break;
661
0
            case 4: vars.tk->fmt.video.multiview_mode = MULTIVIEW_STEREO_CHECKERBOARD;
662
0
                    vars.tk->fmt.video.b_multiview_right_eye_first = true;    break;
663
0
            case 5: vars.tk->fmt.video.multiview_mode = MULTIVIEW_STEREO_CHECKERBOARD; break;
664
0
            case 6: vars.tk->fmt.video.multiview_mode = MULTIVIEW_STEREO_ROW;
665
0
                    vars.tk->fmt.video.b_multiview_right_eye_first = true;    break;
666
0
            case 7: vars.tk->fmt.video.multiview_mode = MULTIVIEW_STEREO_ROW; break;
667
0
            case 8: vars.tk->fmt.video.multiview_mode = MULTIVIEW_STEREO_COL;
668
0
                    vars.tk->fmt.video.b_multiview_right_eye_first = true;    break;
669
0
            case 9: vars.tk->fmt.video.multiview_mode = MULTIVIEW_STEREO_COL; break;
670
0
            case 11: vars.tk->fmt.video.multiview_mode = MULTIVIEW_STEREO_SBS;
671
0
                     vars.tk->fmt.video.b_multiview_right_eye_first = true;    break;
672
0
            case 13: vars.tk->fmt.video.multiview_mode = MULTIVIEW_STEREO_FRAME; break;
673
0
            case 14: vars.tk->fmt.video.multiview_mode = MULTIVIEW_STEREO_FRAME;
674
0
                    vars.tk->fmt.video.b_multiview_right_eye_first = true;    break;
675
0
            default:
676
0
            case 10: case 12:
677
0
                debug( vars, " unsupported Stereo Mode=%u", static_cast<uint8_t>( stereo ) ) ;
678
0
            }
679
0
            debug( vars, "Track Video Stereo Mode=%u", static_cast<uint8_t>( stereo ) ) ;
680
0
        }
681
35
        E_CASE( KaxVideoPixelWidth, vwidth )
682
35
        {
683
16
            ONLY_FMT(VIDEO);
684
16
            vars.tk->fmt.video.i_width += static_cast<uint32_t>( vwidth );
685
16
            debug( vars, "width=%u", vars.tk->fmt.video.i_width );
686
16
        }
687
35
        E_CASE( KaxVideoPixelHeight, vheight )
688
35
        {
689
16
            ONLY_FMT(VIDEO);
690
16
            vars.tk->fmt.video.i_height += static_cast<uint32_t>( vheight );
691
16
            debug( vars, "height=%u", vars.tk->fmt.video.i_height );
692
16
        }
693
35
        E_CASE( KaxVideoDisplayWidth, vwidth )
694
35
        {
695
6
            ONLY_FMT(VIDEO);
696
6
            vars.track_video_info.i_display_width = static_cast<uint32_t>( vwidth );
697
6
            debug( vars, "display width=%u", vars.track_video_info.i_display_width );
698
6
        }
699
35
        E_CASE( KaxVideoDisplayHeight, vheight )
700
35
        {
701
5
            ONLY_FMT(VIDEO);
702
5
            vars.track_video_info.i_display_height = static_cast<uint32_t>( vheight );
703
5
            debug( vars, "display height=%u", vars.track_video_info.i_display_height );
704
5
        }
705
35
        E_CASE( KaxVideoPixelCropBottom, cropval )
706
35
        {
707
0
            ONLY_FMT(VIDEO);
708
0
            vars.track_video_info.i_crop_bottom = static_cast<uint32_t>( cropval );
709
0
            debug( vars, "crop pixel bottom=%u", vars.track_video_info.i_crop_bottom );
710
0
        }
711
35
        E_CASE( KaxVideoPixelCropTop, cropval )
712
35
        {
713
0
            ONLY_FMT(VIDEO);
714
0
            vars.track_video_info.i_crop_top = static_cast<uint32_t>( cropval );
715
0
            debug( vars, "crop pixel top=%u", vars.track_video_info.i_crop_top );
716
0
        }
717
35
        E_CASE( KaxVideoPixelCropRight, cropval )
718
35
        {
719
0
            ONLY_FMT(VIDEO);
720
0
            vars.track_video_info.i_crop_right = static_cast<uint32_t>( cropval );
721
0
            debug( vars, "crop pixel right=%u", vars.track_video_info.i_crop_right );
722
0
        }
723
35
        E_CASE( KaxVideoPixelCropLeft, cropval )
724
35
        {
725
0
            ONLY_FMT(VIDEO);
726
0
            vars.track_video_info.i_crop_left = static_cast<uint32_t>( cropval );
727
0
            debug( vars, "crop pixel left=%u", vars.track_video_info.i_crop_left );
728
0
        }
729
35
        E_CASE( KaxVideoDisplayUnit, vdmode )
730
35
        {
731
0
            ONLY_FMT(VIDEO);
732
0
            vars.track_video_info.i_display_unit = static_cast<uint8_t>( vdmode );
733
0
            const char *psz_unit;
734
0
            switch (vars.track_video_info.i_display_unit)
735
0
            {
736
0
            case 0:  psz_unit = "pixels"; break;
737
0
            case 1:  psz_unit = "centimeters"; break;
738
0
            case 2:  psz_unit = "inches"; break;
739
0
            case 3:  psz_unit = "dar"; break;
740
0
            default: psz_unit = "unknown"; break;
741
0
            }
742
0
            debug( vars, "Track Video Display Unit=%s", psz_unit );
743
0
        }
744
        E_CASE( KaxVideoAspectRatio, ratio ) // UNUSED
745
35
        {
746
0
            ONLY_FMT(VIDEO);
747
0
            debug( vars, "Track Video Aspect Ratio Type=%u", static_cast<uint8_t>( ratio ) ) ;
748
0
        }
749
35
        E_CASE( KaxVideoFrameRate, vfps )
750
35
        {
751
0
            ONLY_FMT(VIDEO);
752
0
            vars.tk->f_fps = std::max( static_cast<float>(vfps) , 1.0f );
753
0
            debug( vars, "fps=%f", vars.tk->f_fps );
754
0
        }
755
35
        E_CASE( KaxVideoColourSpace, colourspace )
756
35
        {
757
0
            ONLY_FMT(VIDEO);
758
0
            if ( colourspace.ValidateSize() )
759
0
            {
760
0
                vars.tk->fmt.i_codec = GetFOURCC( colourspace.GetBuffer() );
761
0
                debug( vars, "Colour Space=%4.4s", (const char*)&vars.tk->fmt.i_codec );
762
0
            }
763
0
        }
764
35
#if LIBMATROSKA_VERSION >= 0x010405
765
35
        E_CASE( KaxVideoColour, colours)
766
35
        {
767
0
            ONLY_FMT(VIDEO);
768
0
            debug( vars, "Video Colors");
769
0
            if (vars.tk->fmt.i_cat != VIDEO_ES ) {
770
0
                msg_Err( vars.p_demuxer, "Video colors elements not allowed for this track" );
771
0
            } else {
772
0
            vars.level += 1;
773
0
            dispatcher.iterate (colours.begin (), colours.end (), &vars );
774
0
            vars.level -= 1;
775
0
            }
776
0
        }
777
35
        E_CASE( KaxVideoColourRange, range )
778
35
        {
779
0
            ONLY_FMT(VIDEO);
780
0
            const char *name = nullptr;
781
0
            switch( static_cast<uint8_t>(range) )
782
0
            {
783
0
            case 1:
784
0
                vars.tk->fmt.video.color_range = COLOR_RANGE_LIMITED;
785
0
                name ="limited";
786
0
                break;
787
0
            case 2:
788
0
                vars.tk->fmt.video.color_range = COLOR_RANGE_FULL;
789
0
                name ="full";
790
0
                break;
791
0
            case 3: // Matrix coefficients + Transfer characteristics
792
0
            default:
793
0
                debug( vars, "Unsupported Colour Range=%d", static_cast<uint8_t>(range) );
794
0
            }
795
0
            if (name != nullptr) debug( vars, "Range=%s", name );
796
0
        }
797
35
        E_CASE( KaxVideoColourTransferCharacter, transfer )
798
35
        {
799
0
            ONLY_FMT(VIDEO);
800
0
            vars.tk->fmt.video.transfer = iso_23001_transfer_to_vlc( static_cast<uint8_t>(transfer) );
801
0
            const char *name = nullptr;
802
0
            switch( static_cast<uint8_t>(transfer) )
803
0
            {
804
0
            case 1: name = "BT-709";
805
0
                break;
806
0
            case 4: name = "BT.470BM";
807
0
                break;
808
0
            case 5: name = "BT.470BG";
809
0
                break;
810
0
            case 6: name = "SMPTE 170M";
811
0
                break;
812
0
            case 7: name = "SMPTE 240M";
813
0
                break;
814
0
            case 8: name = "linear";
815
0
                break;
816
0
            case 13: name = "sRGB/sYCC";
817
0
                break;
818
0
            case 16: name = "BT.2100 PQ";
819
0
                break;
820
0
            case 18: name = "HLG";
821
0
                break;
822
0
            case 9:  // Log
823
0
            case 10: // Log SQRT
824
0
            case 11: // IEC 61966-2-4
825
0
            case 12: // ITU-R BT.1361 Extended Colour Gamut
826
0
            case 14: // ITU-R BT.2020 10 bit
827
0
            case 15: // ITU-R BT.2020 12 bit
828
0
            case 17: // SMPTE ST 428-1
829
0
            default:
830
0
                break;
831
0
            }
832
0
            if (vars.tk->fmt.video.transfer == TRANSFER_FUNC_UNDEF)
833
0
                debug( vars, "Unsupported Colour Transfer=%d", static_cast<uint8_t>(transfer) );
834
0
            else if (name == nullptr)
835
0
                debug( vars, "Colour Transfer=%d", static_cast<uint8_t>(transfer) );
836
0
            else
837
0
                debug( vars, "Colour Transfer=%s", name );
838
0
        }
839
35
        E_CASE( KaxVideoColourPrimaries, primaries )
840
35
        {
841
0
            ONLY_FMT(VIDEO);
842
0
            vars.tk->fmt.video.primaries = iso_23001_primaries_to_vlc( static_cast<uint8_t>(primaries) );
843
0
            const char *name = nullptr;
844
0
            switch( static_cast<uint8_t>(primaries) )
845
0
            {
846
0
            case 1: name = "BT-709";
847
0
                break;
848
0
            case 4: name = "BT.470M";
849
0
                break;
850
0
            case 5: name = "BT.470BG";
851
0
                break;
852
0
            case 6: name = "SMPTE 170M";
853
0
                break;
854
0
            case 7: name = "SMPTE 240M";
855
0
                break;
856
0
            case 9: name = "BT.2020";
857
0
                break;
858
0
            case 8:  // FILM
859
0
            case 10: // SMPTE ST 428-1
860
0
            case 22: // JEDEC P22 phosphors
861
0
            default:
862
0
                break;
863
0
            }
864
0
            if (vars.tk->fmt.video.primaries == COLOR_PRIMARIES_UNDEF)
865
0
                debug( vars, "Unsupported Colour Primaries=%d", static_cast<uint8_t>(primaries) );
866
0
            else if (name == nullptr)
867
0
                debug( vars, "Colour Primaries=%s", static_cast<uint8_t>(primaries) );
868
0
            else
869
0
                debug( vars, "Colour Primaries=%s", name );
870
0
        }
871
35
        E_CASE( KaxVideoColourMatrix, matrix )
872
35
        {
873
0
            ONLY_FMT(VIDEO);
874
0
            vars.tk->fmt.video.space = iso_23001_matrix_coeffs_to_vlc( static_cast<uint8_t>(matrix) );
875
0
            const char *name = nullptr;
876
0
            switch( static_cast<uint8_t>(matrix) )
877
0
            {
878
0
            case 1: name = "BT-709";
879
0
                break;
880
0
            case 6: name = "SMPTE 170M";
881
0
                break;
882
0
            case 7: name = "SMPTE 240M";
883
0
                break;
884
0
            case 9: name = "BT.2020 Non-constant Luminance";
885
0
                break;
886
0
            case 10: name = "BT.2020 Constant Luminance";
887
0
                break;
888
0
            case 0: // Identity
889
0
            case 2: // unspecified
890
0
            case 3: // reserved
891
0
            case 4: // US FCC 73.682
892
0
            case 5: // ITU-R BT.470BG
893
0
            case 8: // YCoCg
894
0
            case 11: // SMPTE ST 2085
895
0
            case 12: // Chroma-derived Non-constant Luminance
896
0
            case 13: // Chroma-derived Constant Luminance
897
0
            case 14: // ITU-R BT.2100
898
0
            default:
899
0
                break;
900
0
            }
901
0
            if (vars.tk->fmt.video.space == COLOR_SPACE_UNDEF)
902
0
                debug( vars, "Unsupported Colour Matrix=%d", static_cast<uint8_t>(matrix) );
903
0
            else if (name == nullptr)
904
0
                debug( vars, "Colour Matrix=%d", static_cast<uint8_t>(matrix) );
905
0
            else
906
0
                debug( vars, "Colour Matrix=%s", name );
907
0
        }
908
35
        E_CASE( KaxVideoChromaSitHorz, chroma_hor )
909
35
        {
910
0
            ONLY_FMT(VIDEO);
911
0
            const char *name = nullptr;
912
0
            vars.track_video_info.chroma_sit_horizontal = static_cast<uint8_t>(chroma_hor);
913
0
            switch( static_cast<uint8_t>(chroma_hor) )
914
0
            {
915
0
            case 0: name = "unspecified"; break;
916
0
            case 1: name = "left";        break;
917
0
            case 2: name = "center";      break;
918
0
            default:
919
0
                debug( vars, "Unsupported Horizontal Chroma Siting=%d", static_cast<uint8_t>(chroma_hor) );
920
0
            }
921
0
            if (name != nullptr) debug( vars, "Chroma Siting Horizontal=%s", name);
922
0
        }
923
35
        E_CASE( KaxVideoChromaSitVert, chroma_ver )
924
35
        {
925
0
            ONLY_FMT(VIDEO);
926
0
            const char *name = nullptr;
927
0
            vars.track_video_info.chroma_sit_vertical = static_cast<uint8_t>(chroma_ver);
928
0
            switch( static_cast<uint8_t>(chroma_ver) )
929
0
            {
930
0
            case 0: name = "unspecified"; break;
931
0
            case 1: name = "left";        break;
932
0
            case 2: name = "center";      break;
933
0
            default:
934
0
                debug( vars, "Unsupported Vertical Chroma Siting=%d", static_cast<uint8_t>(chroma_ver) );
935
0
            }
936
0
            if (name != nullptr) debug( vars, "Chroma Siting Vertical=%s", name);
937
0
        }
938
35
        E_CASE( KaxVideoColourMaxCLL, maxCLL )
939
35
        {
940
0
            ONLY_FMT(VIDEO);
941
0
            debug( vars, "Video Max Pixel Brightness");
942
0
            vars.tk->fmt.video.lighting.MaxCLL = static_cast<uint16_t>(maxCLL);
943
0
        }
944
35
        E_CASE( KaxVideoColourMaxFALL, maxFALL )
945
35
        {
946
0
            ONLY_FMT(VIDEO);
947
0
            debug( vars, "Video Max Frame Brightness");
948
0
            vars.tk->fmt.video.lighting.MaxFALL = static_cast<uint16_t>(maxFALL);
949
0
        }
950
35
        E_CASE( KaxVideoColourMasterMeta, mastering )
951
35
        {
952
0
            ONLY_FMT(VIDEO);
953
0
            debug( vars, "Video Mastering Metadata");
954
0
            if (vars.tk->fmt.i_cat != VIDEO_ES ) {
955
0
                msg_Err( vars.p_demuxer, "Video metadata elements not allowed for this track" );
956
0
            } else {
957
0
            vars.level += 1;
958
0
            dispatcher.iterate (mastering.begin (), mastering.end (), &vars );
959
0
            vars.level -= 1;
960
0
            }
961
0
        }
962
35
        E_CASE( KaxVideoLuminanceMax, maxLum )
963
35
        {
964
0
            ONLY_FMT(VIDEO);
965
0
            debug( vars, "Video Luminance Max");
966
0
            vars.tk->fmt.video.mastering.max_luminance = static_cast<float>(maxLum) * 10000.f;
967
0
        }
968
35
        E_CASE( KaxVideoLuminanceMin, minLum )
969
35
        {
970
0
            ONLY_FMT(VIDEO);
971
0
            debug( vars, "Video Luminance Min");
972
0
            vars.tk->fmt.video.mastering.min_luminance = static_cast<float>(minLum) * 10000.f;
973
0
        }
974
35
        E_CASE( KaxVideoGChromaX, chroma )
975
35
        {
976
0
            ONLY_FMT(VIDEO);
977
0
            debug( vars, "Video Green Chroma X");
978
0
            vars.tk->fmt.video.mastering.primaries[0] = static_cast<float>(chroma) * 50000.f;
979
0
        }
980
35
        E_CASE( KaxVideoGChromaY, chroma )
981
35
        {
982
0
            ONLY_FMT(VIDEO);
983
0
            debug( vars, "Video Green Chroma Y");
984
0
            vars.tk->fmt.video.mastering.primaries[1] = static_cast<float>(chroma) * 50000.f;
985
0
        }
986
35
        E_CASE( KaxVideoBChromaX, chroma )
987
35
        {
988
0
            ONLY_FMT(VIDEO);
989
0
            debug( vars, "Video Blue Chroma X");
990
0
            vars.tk->fmt.video.mastering.primaries[2] = static_cast<float>(chroma) * 50000.f;
991
0
        }
992
35
        E_CASE( KaxVideoBChromaY, chroma )
993
35
        {
994
0
            ONLY_FMT(VIDEO);
995
0
            debug( vars, "Video Blue Chroma Y");
996
0
            vars.tk->fmt.video.mastering.primaries[3] = static_cast<float>(chroma) * 50000.f;
997
0
        }
998
35
        E_CASE( KaxVideoRChromaX, chroma )
999
35
        {
1000
0
            ONLY_FMT(VIDEO);
1001
0
            debug( vars, "Video Red Chroma X");
1002
0
            vars.tk->fmt.video.mastering.primaries[4] = static_cast<float>(chroma) * 50000.f;
1003
0
        }
1004
35
        E_CASE( KaxVideoRChromaY, chroma )
1005
35
        {
1006
0
            ONLY_FMT(VIDEO);
1007
0
            debug( vars, "Video Red Chroma Y");
1008
0
            vars.tk->fmt.video.mastering.primaries[5] = static_cast<float>(chroma) * 50000.f;
1009
0
        }
1010
35
        E_CASE( KaxVideoWhitePointChromaX, white )
1011
35
        {
1012
0
            ONLY_FMT(VIDEO);
1013
0
            debug( vars, "Video WhitePoint X");
1014
0
            vars.tk->fmt.video.mastering.white_point[0] = static_cast<float>(white) * 50000.f;
1015
0
        }
1016
35
        E_CASE( KaxVideoWhitePointChromaY, white )
1017
35
        {
1018
0
            ONLY_FMT(VIDEO);
1019
0
            debug( vars, "Video WhitePoint Y");
1020
0
            vars.tk->fmt.video.mastering.white_point[1] = static_cast<float>(white) * 50000.f;
1021
0
        }
1022
35
#endif
1023
35
        E_CASE( KaxTrackAudio, tka ) {
1024
11
            ONLY_FMT(AUDIO);
1025
11
            debug( vars, "Track Audio");
1026
11
            vars.level += 1;
1027
11
            dispatcher.iterate( tka.begin(), tka.end(), &vars );
1028
11
            vars.level -= 1;
1029
11
        }
1030
35
        E_CASE( KaxAudioSamplingFreq, afreq )
1031
35
        {
1032
11
            ONLY_FMT(AUDIO);
1033
11
            float const value = static_cast<float>( afreq );
1034
1035
11
            vars.tk->i_original_rate  = value;
1036
11
            vars.tk->fmt.audio.i_rate = value;
1037
1038
11
            debug( vars, "afreq=%d", vars.tk->fmt.audio.i_rate ) ;
1039
11
        }
1040
35
        E_CASE( KaxAudioOutputSamplingFreq, afreq )
1041
35
        {
1042
1
            ONLY_FMT(AUDIO);
1043
1
            vars.tk->fmt.audio.i_rate = static_cast<float>( afreq );
1044
1
            debug( vars, "aoutfreq=%d", vars.tk->fmt.audio.i_rate ) ;
1045
1
        }
1046
35
        E_CASE( KaxAudioChannels, achan )
1047
35
        {
1048
10
            ONLY_FMT(AUDIO);
1049
10
            vars.tk->fmt.audio.i_channels = static_cast<uint8_t>( achan );
1050
10
            debug( vars, "achan=%u", vars.tk->fmt.audio.i_channels );
1051
10
        }
1052
35
        E_CASE( KaxAudioBitDepth, abits )
1053
35
        {
1054
4
            ONLY_FMT(AUDIO);
1055
4
            vars.tk->fmt.audio.i_bitspersample = static_cast<uint8_t>( abits );
1056
4
            debug( vars, "abits=%u", vars.tk->fmt.audio.i_bitspersample);
1057
4
        }
1058
35
        E_CASE ( EbmlVoid, ) {
1059
0
          VLC_UNUSED( vars );
1060
0
        }
1061
35
        E_CASE_DEFAULT(element) {
1062
0
            debug( vars, "Unknown (%s)", EBML_NAME(&element) );
1063
0
        }
1064
35
    };
1065
1066
35
    MetaDataHandlers::Dispatcher().iterate ( m->begin(), m->end(), &metadata_payload );
1067
1068
35
    vlc_viewpoint_from_euler( &p_track->fmt.video.pose,
1069
35
                              metadata_payload.pose.yaw,
1070
35
                              metadata_payload.pose.pitch,
1071
35
                              metadata_payload.pose.roll);
1072
1073
35
    if( p_track->i_number == 0 )
1074
0
    {
1075
0
        msg_Warn( &sys.demuxer, "Missing KaxTrackNumber, discarding track!" );
1076
0
        delete p_track;
1077
0
        return;
1078
0
    }
1079
1080
35
    if ( bSupported )
1081
35
    {
1082
#ifdef HAVE_ZLIB
1083
        if( p_track->i_compression_type == MATROSKA_COMPRESSION_ZLIB &&
1084
            p_track->i_encoding_scope & MATROSKA_ENCODING_SCOPE_PRIVATE &&
1085
            p_track->i_extra_data && p_track->p_extra_data &&
1086
            zlib_decompress_extra( &sys.demuxer, *p_track ) )
1087
        {
1088
            msg_Err(&sys.demuxer, "Couldn't handle the track %u compression", p_track->i_number );
1089
            delete p_track;
1090
            return;
1091
        }
1092
#endif
1093
35
        if( !TrackInit( p_track ) )
1094
0
        {
1095
0
            msg_Err(&sys.demuxer, "Couldn't init track %u", p_track->i_number );
1096
0
            delete p_track;
1097
0
            return;
1098
0
        }
1099
1100
35
        tracks.insert( std::make_pair( p_track->i_number, std::unique_ptr<mkv_track_t>(p_track) ) ); // TODO: add warning if two tracks have the same key
1101
35
    }
1102
0
    else
1103
0
    {
1104
0
        msg_Err( &sys.demuxer, "Track Entry %u not supported", p_track->i_number );
1105
0
        delete p_track;
1106
0
    }
1107
35
}
1108
1109
#undef ONLY_FMT
1110
1111
/*****************************************************************************
1112
 * ParseTracks:
1113
 *****************************************************************************/
1114
void matroska_segment_c::ParseTracks( KaxTracks *tracks )
1115
16
{
1116
    /* Master elements */
1117
16
    if ( !ReadMaster( *tracks ) )
1118
0
        return;
1119
1120
16
    struct Capture {
1121
16
      matroska_segment_c * obj;
1122
16
      demux_t            * p_demuxer;
1123
1124
16
    } payload = {
1125
16
      this, &sys.demuxer
1126
16
    };
1127
1128
16
    MKV_SWITCH_CREATE( EbmlTypeDispatcher, TrackHandlers, struct Capture )
1129
16
    {
1130
16
        MKV_SWITCH_INIT();
1131
1132
35
        E_CASE( KaxTrackEntry, track_number ) {
1133
35
            vars.obj->ParseTrackEntry( &track_number );
1134
35
        }
1135
16
        E_CASE( EbmlVoid, ) {
1136
0
            VLC_UNUSED( vars );
1137
0
        }
1138
16
        E_CASE_DEFAULT(element) {
1139
10
            MkvTree( *vars.p_demuxer, 2, "Unknown (%s)", EBML_NAME(&element) );
1140
10
        }
1141
16
    };
1142
1143
16
    TrackHandlers::Dispatcher().iterate( tracks->begin(), tracks->end(), &payload );
1144
1145
16
    for (auto &track : matroska_segment_c::tracks)
1146
35
    {
1147
35
        pcr_shift = std::max(pcr_shift, track.second->i_codec_delay);
1148
35
    }
1149
16
}
1150
1151
/*****************************************************************************
1152
 * ParseInfo:
1153
 *****************************************************************************/
1154
void matroska_segment_c::ParseInfo( KaxInfo *info )
1155
16
{
1156
16
    EbmlMaster  *m = info;
1157
1158
16
    if ( !ReadMaster( *info ) )
1159
0
        return;
1160
1161
16
    struct InfoHandlerPayload {
1162
16
        demux_t            * p_demuxer;
1163
16
        matroska_segment_c * obj;
1164
16
        EbmlMaster        *&   m;
1165
16
        double             f_duration;
1166
1167
16
    } captures = { &sys.demuxer, this, m, -1. };
1168
1169
16
    MKV_SWITCH_CREATE(EbmlTypeDispatcher, InfoHandlers, InfoHandlerPayload)
1170
16
    {
1171
16
        MKV_SWITCH_INIT();
1172
1173
16
        static void debug (InfoHandlerPayload& vars, char const * fmt, ...)
1174
75
        {
1175
75
            va_list args; va_start( args, fmt );
1176
75
            MkvTree_va( *vars.p_demuxer, 2, fmt, args);
1177
75
            va_end( args );
1178
75
        }
1179
16
        E_CASE( KaxSegmentUID, uid )
1180
16
        {
1181
11
            if ( vars.obj->p_segment_uid == NULL )
1182
11
            {
1183
11
                vars.obj->p_segment_uid = new KaxSegmentUID( uid );
1184
11
            }
1185
11
            debug( vars, "UID=%" PRIx64, *reinterpret_cast<uint64_t*>( vars.obj->p_segment_uid->GetBuffer() ) );
1186
11
        }
1187
16
        E_CASE( KaxPrevUID, uid )
1188
16
        {
1189
0
            if ( vars.obj->p_prev_segment_uid == NULL )
1190
0
            {
1191
0
                vars.obj->p_prev_segment_uid = new KaxPrevUID( uid );
1192
0
                vars.obj->b_ref_external_segments = true;
1193
0
            }
1194
0
            debug( vars, "PrevUID=%" PRIx64, *reinterpret_cast<uint64_t*>( vars.obj->p_prev_segment_uid->GetBuffer() ) );
1195
0
        }
1196
16
        E_CASE( KaxNextUID, uid )
1197
16
        {
1198
0
            if ( vars.obj->p_next_segment_uid == NULL )
1199
0
            {
1200
0
                vars.obj->p_next_segment_uid = new KaxNextUID( uid );
1201
0
                vars.obj->b_ref_external_segments = true;
1202
0
            }
1203
0
            debug( vars, "NextUID=%" PRIx64, *reinterpret_cast<uint64_t*>( vars.obj->p_next_segment_uid->GetBuffer() ) );
1204
0
        }
1205
16
        E_CASE( KaxTimestampScale, tcs )
1206
16
        {
1207
11
            vars.obj->i_timescale = static_cast<uint64_t>( tcs );
1208
11
            debug( vars, "TimecodeScale=%" PRId64, vars.obj->i_timescale );
1209
11
        }
1210
16
        E_CASE( KaxDuration, dur )
1211
16
        {
1212
14
            vars.f_duration = static_cast<double>( dur );
1213
14
            debug( vars, "Duration=%.0f", vars.f_duration );
1214
14
        }
1215
16
        E_CASE( KaxMuxingApp, mapp )
1216
16
        {
1217
16
            vars.obj->psz_muxing_application = ToUTF8( UTFstring( mapp ) );
1218
16
            debug( vars, "Muxing Application=%s", vars.obj->psz_muxing_application );
1219
16
        }
1220
16
        E_CASE( KaxWritingApp, wapp )
1221
16
        {
1222
16
            vars.obj->psz_writing_application = ToUTF8( UTFstring( wapp ) );
1223
16
            debug( vars, "Writing Application=%s", vars.obj->psz_writing_application );
1224
16
        }
1225
16
        E_CASE( KaxSegmentFilename, sfn )
1226
16
        {
1227
0
            vars.obj->psz_segment_filename = ToUTF8( UTFstring( sfn ) );
1228
0
            debug( vars, "Segment Filename=%s", vars.obj->psz_segment_filename );
1229
0
        }
1230
16
        E_CASE( KaxTitle, title )
1231
16
        {
1232
0
            vars.obj->psz_title = ToUTF8( UTFstring( title ) );
1233
0
            debug( vars, "Title=%s", vars.obj->psz_title );
1234
0
        }
1235
16
        E_CASE( KaxSegmentFamily, uid )
1236
16
        {
1237
0
            vars.obj->families.push_back( new KaxSegmentFamily(uid) );
1238
0
            debug( vars, "Family=%" PRIx64, *reinterpret_cast<uint64_t*>( uid.GetBuffer() ) );
1239
0
        }
1240
16
        E_CASE( KaxDateUTC, date )
1241
16
        {
1242
7
            struct tm tmres;
1243
7
            char   buffer[25];
1244
7
            time_t i_date = date.GetEpochDate();
1245
1246
7
            if( gmtime_r( &i_date, &tmres ) &&
1247
7
                strftime( buffer, sizeof(buffer), "%a %b %d %H:%M:%S %Y",
1248
7
                          &tmres ) )
1249
7
            {
1250
7
                vars.obj->psz_date_utc = strdup( buffer );
1251
7
                debug( vars, "Date=%s", vars.obj->psz_date_utc );
1252
7
            }
1253
7
        }
1254
16
        E_CASE( KaxChapterTranslate, trans )
1255
16
        {
1256
0
            MKV_SWITCH_CREATE( EbmlTypeDispatcher, TranslationHandler, chapter_translation_c* )
1257
0
            {
1258
0
                MKV_SWITCH_INIT();
1259
1260
0
                E_CASE( KaxChapterTranslateEditionUID, uid )
1261
0
                {
1262
0
                    vars->editions.push_back( static_cast<uint64_t>( uid ) );
1263
0
                }
1264
0
                E_CASE( KaxChapterTranslateCodec, codec_id )
1265
0
                {
1266
0
                    vars->codec_id = static_cast<uint32_t>( codec_id );
1267
0
                }
1268
0
                E_CASE( KaxChapterTranslateID, translated_id )
1269
0
                {
1270
0
                    vars->p_translated = new KaxChapterTranslateID( translated_id );
1271
0
                }
1272
0
            };
1273
0
            try
1274
0
            {
1275
0
                if ( !vars.obj->ReadMaster( trans ) )
1276
0
                    return;
1277
1278
0
                chapter_translation_c *p_translate = new chapter_translation_c();
1279
1280
0
                TranslationHandler::Dispatcher().iterate(
1281
0
                    trans.begin(), trans.end(), &p_translate
1282
0
                );
1283
1284
0
                vars.obj->translations.push_back( p_translate );
1285
0
            }
1286
0
            catch(...)
1287
0
            {
1288
0
                msg_Err( vars.p_demuxer, "Error while reading Chapter Translate");
1289
0
            }
1290
0
        }
1291
16
        E_CASE( EbmlVoid, )
1292
16
        {
1293
0
            VLC_UNUSED( vars );
1294
0
        }
1295
16
        E_CASE_DEFAULT(element)
1296
16
        {
1297
0
            debug( vars, "Unknown (%s)", EBML_NAME(&element) );
1298
0
        }
1299
16
    };
1300
1301
16
    InfoHandlers::Dispatcher().iterate( m->begin(), m->end(), &captures );
1302
1303
16
    if( captures.f_duration != -1. )
1304
14
        i_duration = VLC_TICK_FROM_NS( captures.f_duration * i_timescale );
1305
16
}
1306
1307
1308
/*****************************************************************************
1309
 * ParseChapterAtom
1310
 *****************************************************************************/
1311
void matroska_segment_c::ParseChapterAtom( int i_level, KaxChapterAtom *ca, chapter_item_c & chapters )
1312
0
{
1313
0
    MkvTree( sys.demuxer, 3, "ChapterAtom (level=%d)", i_level );
1314
1315
0
    struct ChapterPayload {
1316
0
        matroska_segment_c * const       obj;
1317
0
        demux_t            * const p_demuxer;
1318
0
        chapter_item_c     &        chapters;
1319
1320
0
        int& i_level;
1321
0
        int level;
1322
1323
0
    } payload = {
1324
0
        this, &sys.demuxer, chapters,
1325
0
        i_level, 4
1326
0
    };
1327
1328
0
    MKV_SWITCH_CREATE( EbmlTypeDispatcher, ChapterAtomHandlers, ChapterPayload )
1329
0
    {
1330
0
        MKV_SWITCH_INIT();
1331
1332
0
        static void debug (ChapterPayload const& vars, char const * fmt, ...)
1333
0
        {
1334
0
            va_list args; va_start( args, fmt );
1335
0
            MkvTree_va( *vars.p_demuxer, vars.level, fmt, args);
1336
0
            va_end( args );
1337
0
        }
1338
0
        E_CASE( KaxChapterUID, uid )
1339
0
        {
1340
0
            vars.chapters.i_uid = static_cast<uint64_t>( uid );
1341
0
            debug( vars, "ChapterUID=%" PRIx64, vars.chapters.i_uid );
1342
0
        }
1343
0
        E_CASE( KaxChapterFlagHidden, flag )
1344
0
        {
1345
0
            vars.chapters.b_display_seekpoint = static_cast<uint8_t>( flag ) == 0;
1346
0
            debug( vars, "ChapterFlagHidden=%s", vars.chapters.b_display_seekpoint ? "no" : "yes" );
1347
0
        }
1348
0
        E_CASE( KaxChapterSegmentUID, uid )
1349
0
        {
1350
0
            vars.chapters.p_segment_uid = new KaxChapterSegmentUID( uid );
1351
0
            vars.obj->b_ref_external_segments = true;
1352
1353
0
            debug( vars, "ChapterSegmentUID=%" PRIx64, *reinterpret_cast<uint64_t*>( vars.chapters.p_segment_uid->GetBuffer() ) );
1354
0
        }
1355
0
        E_CASE( KaxChapterSegmentEditionUID, euid )
1356
0
        {
1357
0
            vars.chapters.p_segment_edition_uid = new KaxChapterSegmentEditionUID( euid );
1358
1359
0
            debug( vars, "ChapterSegmentEditionUID=%x",
1360
#if LIBMATROSKA_VERSION < 0x010300
1361
              *reinterpret_cast<uint32_t*>( vars.chapters.p_segment_edition_uid->GetBuffer() )
1362
#else
1363
0
              static_cast<uint32_t>( *vars.chapters.p_segment_edition_uid )
1364
0
#endif
1365
0
            );
1366
0
        }
1367
0
        E_CASE( KaxChapterTimeStart, start )
1368
0
        {
1369
0
            vars.chapters.i_start_time = VLC_TICK_FROM_NS(static_cast<uint64_t>( start ));
1370
0
            debug( vars, "ChapterTimeStart=%" PRId64, vars.chapters.i_start_time );
1371
0
        }
1372
0
        E_CASE( KaxChapterTimeEnd, end )
1373
0
        {
1374
0
            vars.chapters.i_end_time = VLC_TICK_FROM_NS(static_cast<uint64_t>( end ));
1375
0
            debug( vars, "ChapterTimeEnd=%" PRId64, vars.chapters.i_end_time );
1376
0
        }
1377
0
        E_CASE( KaxChapterDisplay, chapter_display )
1378
0
        {
1379
0
            debug( vars, "ChapterDisplay" );
1380
1381
0
            vars.level += 1;
1382
0
            dispatcher.iterate( chapter_display.begin(), chapter_display.end(), &vars );
1383
0
            vars.level -= 1;
1384
0
        }
1385
0
        E_CASE( KaxChapterString, name )
1386
0
        {
1387
0
            std::string str_name( UTFstring( name ).GetUTF8() );
1388
1389
0
            for ( int k = 0; k < vars.i_level; k++)
1390
0
                vars.chapters.str_name += '+';
1391
1392
0
            vars.chapters.str_name += ' ';
1393
0
            vars.chapters.str_name += str_name;
1394
0
            vars.chapters.b_user_display = true;
1395
1396
0
            debug( vars, "ChapterString=%s", str_name.c_str() );
1397
0
        }
1398
0
        E_CASE( KaxChapterLanguage, lang )
1399
0
        {
1400
0
            debug( vars, "ChapterLanguage=%s", static_cast<std::string const&>( lang ).c_str() );
1401
0
        }
1402
0
        E_CASE( KaxChapterCountry, ct )
1403
0
        {
1404
0
            debug( vars, "ChapterCountry=%s", static_cast<std::string const&>( ct ).c_str() );
1405
0
        }
1406
1407
0
        E_CASE( KaxChapterProcess, cp )
1408
0
        {
1409
0
            debug( vars, "ChapterProcess" );
1410
1411
0
            if ( !var_InheritBool( vars.p_demuxer, "mkv-use-chapter-codec") )
1412
0
                return;
1413
1414
0
            chapter_codec_cmds_c *p_ccodec = NULL;
1415
1416
0
            for (auto proc : cp)
1417
0
            {
1418
0
                if( MKV_CHECKED_PTR_DECL_CONST( p_codec_id, KaxChapterProcessCodecID, proc ) )
1419
0
                {
1420
0
                    if ( p_codec_id->GetValue() == MATROSKA_CHAPTER_CODEC_NATIVE )
1421
0
                    {
1422
0
                       auto interpreter = vars.obj->sys.GetMatroskaScriptInterpreter();
1423
0
                       if (unlikely(interpreter == nullptr))
1424
0
                            debug( vars, "failed to get the Matroska Script interpreter ");
1425
0
                       else
1426
0
                            p_ccodec = new matroska_script_codec_c(
1427
0
                            vlc_object_logger( &vars.obj->sys.demuxer ),
1428
0
                            vars.obj->sys, *interpreter
1429
0
                            );
1430
0
                    }
1431
0
                    else if ( p_codec_id->GetValue() == MATROSKA_CHAPTER_CODEC_DVD )
1432
0
                    {
1433
0
                        auto interepreter = vars.obj->sys.GetDVDInterpretor();
1434
0
                        if (unlikely(interepreter == nullptr))
1435
0
                            debug( vars, "failed to get the DVD interpreter ");
1436
0
                        else
1437
0
                            p_ccodec = new dvd_chapter_codec_c( vlc_object_logger( &vars.obj->sys.demuxer ), vars.obj->sys, *interepreter );
1438
0
                    }
1439
0
                    break;
1440
0
                }
1441
0
            }
1442
1443
0
            if ( p_ccodec != NULL )
1444
0
            {
1445
0
                for (auto k : cp)
1446
0
                {
1447
0
                    if( MKV_CHECKED_PTR_DECL_CONST( p_private, KaxChapterProcessPrivate, k ) )
1448
0
                    {
1449
0
                        p_ccodec->SetPrivate( *p_private );
1450
0
                    }
1451
0
                    else if ( MKV_CHECKED_PTR_DECL_CONST( cmd, KaxChapterProcessCommand, k ) )
1452
0
                    {
1453
0
                        p_ccodec->AddCommand( *cmd );
1454
0
                    }
1455
0
                }
1456
0
                vars.chapters.codecs.push_back( p_ccodec );
1457
0
            }
1458
0
        }
1459
0
        E_CASE( KaxChapterAtom, atom )
1460
0
        {
1461
0
            chapter_item_c *new_sub_chapter = new chapter_item_c();
1462
0
            new_sub_chapter->p_parent = &vars.chapters;
1463
1464
0
            vars.obj->ParseChapterAtom( vars.i_level+1, &atom, *new_sub_chapter );
1465
0
            vars.chapters.sub_chapters.push_back( new_sub_chapter );
1466
0
        }
1467
0
    };
1468
1469
0
    ChapterAtomHandlers::Dispatcher().iterate( ca->begin(), ca->end(), &payload );
1470
0
}
1471
1472
/*****************************************************************************
1473
 * ParseAttachments:
1474
 *****************************************************************************/
1475
void matroska_segment_c::ParseAttachments( KaxAttachments *attachments )
1476
0
{
1477
0
    if ( !ReadMaster( *attachments ))
1478
0
        return;
1479
1480
0
    KaxAttached *attachedFile = FindChild<KaxAttached>( *attachments );
1481
1482
0
    while( attachedFile )
1483
0
    {
1484
0
        if (attachedFile->GetSize() > 0 )
1485
0
        try {
1486
0
            KaxFileData  &img_data     = GetMandatoryChild<KaxFileData>( *attachedFile );
1487
0
            std::string attached_filename( UTFstring( GetMandatoryChild<KaxFileName>( *attachedFile ) ).GetUTF8() );
1488
0
            auto new_attachment = vlc_input_attachment_New( attached_filename.c_str(),
1489
0
                                                            GetMandatoryChild<KaxMimeType>( *attachedFile ).GetValue().c_str(),
1490
0
                                                            nullptr,
1491
0
                                                            img_data.GetBuffer(),
1492
0
                                                            img_data.GetSize() );
1493
0
            if (new_attachment)
1494
0
            {
1495
0
                msg_Dbg( &sys.demuxer, "|   |   - %s (%s)", new_attachment->psz_name,
1496
0
                        new_attachment->psz_mime );
1497
1498
0
                if( !strncmp( new_attachment->psz_mime, "image/", 6 ) )
1499
0
                {
1500
0
                    char *psz_url;
1501
0
                    if( asprintf( &psz_url, "attachment://%s",
1502
0
                                new_attachment->psz_name ) >= 0 )
1503
0
                    {
1504
0
                        if( !sys.meta )
1505
0
                            sys.meta = vlc_meta_New();
1506
0
                        vlc_meta_SetArtURL( sys.meta, psz_url );
1507
0
                        free( psz_url );
1508
0
                    }
1509
0
                }
1510
0
                sys.stored_attachments.push_back( vlc::wrap_cptr( new_attachment,
1511
0
                                                                &vlc_input_attachment_Release ) );
1512
0
            }
1513
0
        } catch (const MissingMandatory & err) {
1514
0
            msg_Dbg( &sys.demuxer, "%s", err.what());
1515
0
        }
1516
0
        attachedFile = FindNextChild<KaxAttached>( *attachments, *attachedFile );
1517
0
    }
1518
0
}
1519
1520
/*****************************************************************************
1521
 * ParseChapters:
1522
 *****************************************************************************/
1523
void matroska_segment_c::ParseChapters( KaxChapters *chapters )
1524
0
{
1525
0
    if ( !ReadMaster( *chapters ) )
1526
0
        return;
1527
1528
0
    MKV_SWITCH_CREATE( EbmlTypeDispatcher, KaxChapterHandler, matroska_segment_c )
1529
0
    {
1530
0
        MKV_SWITCH_INIT();
1531
0
        E_CASE( KaxEditionEntry, entry )
1532
0
        {
1533
0
            struct EditionPayload {
1534
0
                matroska_segment_c * const obj;
1535
0
                demux_t            * const p_demuxer;
1536
0
                chapter_edition_c  * const p_edition;
1537
1538
0
            } data = { &vars, &vars.sys.demuxer, new chapter_edition_c };
1539
1540
0
            MKV_SWITCH_CREATE( EbmlTypeDispatcher, KaxEditionHandler, EditionPayload )
1541
0
            {
1542
0
                MKV_SWITCH_INIT();
1543
0
                E_CASE( KaxChapterAtom, chapter_atom )
1544
0
                {
1545
0
                    chapter_item_c *new_sub_chapter = new chapter_item_c();
1546
0
                    vars.obj->ParseChapterAtom( 0, &chapter_atom, *new_sub_chapter );
1547
0
                    vars.p_edition->sub_chapters.push_back( new_sub_chapter );
1548
0
                }
1549
0
                E_CASE( KaxEditionUID, euid )
1550
0
                {
1551
0
                    vars.p_edition->i_uid = static_cast<uint64_t> ( euid );
1552
0
                }
1553
0
                E_CASE( KaxEditionFlagOrdered, flag_ordered )
1554
0
                {
1555
0
                    vars.p_edition->b_ordered = var_InheritBool(vars.p_demuxer, "mkv-use-ordered-chapters") && static_cast<uint8_t>( flag_ordered );
1556
0
                }
1557
0
                E_CASE( KaxEditionFlagDefault, flag_default )
1558
0
                {
1559
0
                    if( static_cast<uint8_t>( flag_default ) )
1560
0
                        vars.obj->i_default_edition = vars.obj->stored_editions.size();
1561
0
                }
1562
0
                E_CASE( KaxEditionFlagHidden, flag_hidden )
1563
0
                {
1564
0
                    vars.p_edition->b_hidden = static_cast<uint8_t>( flag_hidden ) != 0;
1565
0
                }
1566
0
                E_CASE( EbmlVoid, el )
1567
0
                {
1568
0
                    VLC_UNUSED( el );
1569
0
                    VLC_UNUSED( vars );
1570
0
                }
1571
0
                E_CASE_DEFAULT( el )
1572
0
                {
1573
0
                    msg_Dbg( vars.p_demuxer, "|   |   |   + Unknown (%s)", EBML_NAME(&el) );
1574
0
                }
1575
0
            };
1576
0
            KaxEditionHandler::Dispatcher().iterate( entry.begin(), entry.end(), &data );
1577
1578
0
            data.obj->stored_editions.push_back( data.p_edition );
1579
0
        }
1580
0
        E_CASE( EbmlVoid, el ) {
1581
0
            VLC_UNUSED( el );
1582
0
            VLC_UNUSED( vars );
1583
0
        }
1584
0
        E_CASE_DEFAULT( el )
1585
0
        {
1586
0
            msg_Dbg( &vars.sys.demuxer, "|   |   + Unknown (%s)", EBML_NAME(&el) );
1587
0
        }
1588
0
    };
1589
1590
0
    KaxChapterHandler::Dispatcher().iterate( chapters->begin(), chapters->end(), this );
1591
0
}
1592
1593
bool matroska_segment_c::ParseCluster( KaxCluster *cluster, bool b_update_start_time, ScopeMode read_fully )
1594
4
{
1595
4
    if (!sys.b_seekable)
1596
0
        return false;
1597
1598
4
    if ( !ReadMaster( *cluster, read_fully ) )
1599
0
        return false;
1600
1601
4
    bool b_has_timecode = false;
1602
1603
4
    for (auto c : *cluster)
1604
4
    {
1605
4
        if( MKV_CHECKED_PTR_DECL_CONST( p_ctc, KaxClusterTimestamp, c ) )
1606
4
        {
1607
4
            cluster->InitTimestamp( static_cast<uint64_t>( *p_ctc ), i_timescale );
1608
4
            _seeker.add_cluster( cluster );
1609
4
            b_has_timecode = true;
1610
4
            break;
1611
4
        }
1612
4
    }
1613
1614
4
    if( !b_has_timecode )
1615
0
    {
1616
0
        msg_Err( &sys.demuxer, "Detected cluster without mandatory timecode" );
1617
0
        return false;
1618
0
    }
1619
1620
4
    if( b_update_start_time )
1621
0
        i_mk_start_time = VLC_TICK_FROM_NS( cluster->GlobalTimestamp() );
1622
1623
4
    return true;
1624
4
}
1625
1626
12
#define ONLY_FMT(t) if(vars.p_tk->fmt.i_cat != t ## _ES) \
1627
12
    throw std::runtime_error( "Mismatching track type" );
1628
1629
bool matroska_segment_c::TrackInit( mkv_track_t * p_tk )
1630
35
{
1631
35
    if( p_tk->codec.empty() )
1632
0
    {
1633
0
        msg_Err( &sys.demuxer, "Empty codec id" );
1634
0
        p_tk->fmt.i_codec = VLC_CODEC_UNKNOWN;
1635
0
        return true;
1636
0
    }
1637
1638
35
    struct HandlerPayload {
1639
35
        matroska_segment_c * obj;
1640
35
        mkv_track_t        * p_tk;
1641
35
        es_format_t        * p_fmt;
1642
35
        demux_t            * p_demuxer;
1643
35
    } captures = {
1644
35
        this, p_tk, &p_tk->fmt, &sys.demuxer
1645
35
    };
1646
1647
35
    MKV_SWITCH_CREATE( StringDispatcher, TrackCodecHandlers, HandlerPayload )
1648
35
    {
1649
35
        MKV_SWITCH_INIT();
1650
1651
35
        S_CASE("V_MS/VFW/FOURCC") {
1652
4
            if( vars.p_tk->i_extra_data < (int)sizeof( VLC_BITMAPINFOHEADER ) )
1653
0
            {
1654
0
                msg_Err(vars.p_demuxer, "missing/invalid VLC_BITMAPINFOHEADER" );
1655
0
                vars.p_fmt->i_codec = VLC_CODEC_UNKNOWN;
1656
0
            }
1657
4
            else
1658
4
            {
1659
4
                ONLY_FMT(VIDEO);
1660
4
                VLC_BITMAPINFOHEADER *p_bih = (VLC_BITMAPINFOHEADER*)vars.p_tk->p_extra_data;
1661
1662
4
                vars.p_fmt->video.i_width = GetDWLE( &p_bih->biWidth );
1663
4
                vars.p_fmt->video.i_height= GetDWLE( &p_bih->biHeight );
1664
4
                vars.p_fmt->i_codec       = GetFOURCC( &p_bih->biCompression );
1665
1666
                /* Very unlikely yet possible: bug #5659*/
1667
4
                const size_t min_extra = std::min(static_cast<size_t>(GetDWLE(&p_bih->biSize)),
1668
4
                                                  vars.p_tk->i_extra_data);
1669
4
                if ( min_extra > sizeof( VLC_BITMAPINFOHEADER ))
1670
0
                {
1671
0
                    vars.p_fmt->i_extra = min_extra - sizeof( VLC_BITMAPINFOHEADER );
1672
0
                    vars.p_fmt->p_extra = xmalloc( vars.p_fmt->i_extra );
1673
0
                    if (likely(vars.p_fmt->p_extra != NULL))
1674
0
                        memcpy( vars.p_fmt->p_extra, &p_bih[1], vars.p_fmt->i_extra );
1675
0
                    else
1676
0
                        vars.p_fmt->i_extra = 0;
1677
0
                }
1678
4
                else if( vars.p_fmt->i_codec == VLC_FOURCC('W','V','C','1') )
1679
0
                {
1680
0
                    vars.p_fmt->video.i_width = 0;
1681
0
                    vars.p_fmt->video.i_height = 0;
1682
0
                    vars.p_fmt->b_packetized = false;
1683
0
                }
1684
4
            }
1685
4
            vars.p_tk->b_dts_only = true;
1686
4
        }
1687
35
        S_CASE("V_MPEG1") {
1688
0
            vars.p_fmt->i_codec = VLC_CODEC_MPGV;
1689
0
            fill_extra_data( vars.p_tk, 0 );
1690
0
        }
1691
35
        S_CASE("V_MPEG2") {
1692
0
            vars.p_fmt->i_codec = VLC_CODEC_MPGV;
1693
0
            if (vars.obj->psz_muxing_application != NULL &&
1694
0
                    strstr(vars.obj->psz_muxing_application,"libmakemkv"))
1695
0
                vars.p_fmt->b_packetized = false;
1696
0
            fill_extra_data( vars.p_tk, 0 );
1697
0
        }
1698
35
        S_CASE("V_THEORA") {
1699
2
            vars.p_fmt->i_codec = VLC_CODEC_THEORA;
1700
2
            vars.p_tk->b_pts_only = true;
1701
2
            fill_extra_data( vars.p_tk, 0 );
1702
2
        }
1703
35
        static void v_real_helper (vlc_fourcc_t codec, HandlerPayload& vars)
1704
35
        {
1705
0
            vars.p_fmt->i_codec   = codec;
1706
1707
            /* Extract the framerate from the header */
1708
0
            uint8_t *p = vars.p_tk->p_extra_data;
1709
1710
0
            if (
1711
0
                vars.p_tk->i_extra_data >= 26 && !memcmp(p+4, "VIDORV", 6) && strchr("34", p[10]) && p[11] == '0')
1712
0
            {
1713
0
                ONLY_FMT(VIDEO);
1714
0
                vars.p_tk->fmt.video.i_frame_rate      = p[22] << 24 | p[23] << 16 | p[24] << 8 | p[25] << 0;
1715
0
                vars.p_tk->fmt.video.i_frame_rate_base = 65536;
1716
0
            }
1717
1718
0
            fill_extra_data( vars.p_tk, 26 );
1719
0
        }
1720
35
        S_CASE("V_REAL/RV10") { v_real_helper (VLC_CODEC_RV10, vars ); }
1721
35
        S_CASE("V_REAL/RV20") { v_real_helper (VLC_CODEC_RV20, vars ); }
1722
35
        S_CASE("V_REAL/RV30") { v_real_helper (VLC_CODEC_RV30, vars ); }
1723
35
        S_CASE("V_REAL/RV40") { v_real_helper (VLC_CODEC_RV40, vars ); }
1724
35
        S_CASE("V_DIRAC")     {
1725
0
            vars.p_fmt->i_codec = VLC_CODEC_DIRAC;
1726
0
        }
1727
35
        S_CASE("V_VP8") {
1728
5
            vars.p_fmt->i_codec = VLC_CODEC_VP8;
1729
5
            if (vars.p_tk->b_has_alpha)
1730
5
                vars.p_fmt->i_level = 0x1000; // mark as containing alpha data
1731
5
            vars.p_tk->b_pts_only = true;
1732
5
        }
1733
35
        S_CASE("V_VP9") {
1734
0
            vars.p_fmt->i_codec = VLC_CODEC_VP9;
1735
0
            if (vars.p_tk->b_has_alpha)
1736
0
                vars.p_fmt->i_level = 0x1000; // mark as containing alpha data
1737
0
            vars.p_tk->b_pts_only = true;
1738
1739
0
            fill_extra_data( vars.p_tk, 0 );
1740
0
            if (vars.p_tk->fmt.i_extra)
1741
0
            {
1742
0
                const auto * VP9CodecFeatures = static_cast<const uint8_t*>(vars.p_tk->fmt.p_extra);
1743
0
                size_t remain = vars.p_tk->fmt.i_extra;
1744
0
                while (remain >= 3)
1745
0
                {
1746
0
                    uint8_t length = VP9CodecFeatures[1];
1747
0
                    switch (VP9CodecFeatures[0])
1748
0
                    {
1749
0
                        case 1: // Profile
1750
0
                            if (length == 1)
1751
0
                                vars.p_fmt->i_profile = VP9CodecFeatures[2];
1752
0
                            break;
1753
0
                        case 2: // Level
1754
0
                            if (length == 1) {
1755
0
                                if (es_format_HasVpxAlpha(vars.p_fmt))
1756
0
                                    vars.p_fmt->i_level |= VP9CodecFeatures[2];
1757
0
                                else
1758
0
                                    vars.p_fmt->i_level = VP9CodecFeatures[2];
1759
0
                            }
1760
0
                            break;
1761
0
                        case 3: // Bit Depth
1762
0
                        case 4: // Chroma Subsampling
1763
0
                        default:
1764
0
                            break;
1765
0
                    }
1766
0
                    VP9CodecFeatures += 1 + 1 + length;
1767
0
                    remain -= 1 + 1 + length;
1768
0
                }
1769
0
            }
1770
0
        }
1771
35
        S_CASE("V_AV1") {
1772
0
            vars.p_fmt->i_codec = VLC_CODEC_AV1;
1773
0
            vars.p_tk->b_pts_only = true;
1774
1775
0
            fill_extra_data( vars.p_tk, 0 );
1776
0
            if (vars.p_fmt->i_extra <= 4)
1777
0
                vars.p_fmt->b_packetized = false; // force full extradata by the packetizer
1778
0
        }
1779
35
        S_CASE("V_CAVS") {
1780
0
            vars.p_fmt->i_codec = VLC_CODEC_CAVS;
1781
0
        }
1782
35
        S_CASE("V_AVS2") {
1783
0
            vars.p_fmt->i_codec = VLC_CODEC_CAVS2;
1784
0
        }
1785
35
        S_CASE("V_AVS3") {
1786
0
            vars.p_fmt->i_codec = VLC_CODEC_CAVS3;
1787
0
        }
1788
35
        S_CASE("V_MPEG4/MS/V3") {
1789
0
            vars.p_fmt->i_codec = VLC_CODEC_DIV3;
1790
0
        }
1791
35
        S_CASE("V_MPEG4/ISO/AVC") {
1792
5
            vars.p_fmt->i_codec = VLC_FOURCC( 'a','v','c','1' );
1793
5
            fill_extra_data( vars.p_tk, 0 );
1794
5
        }
1795
35
        S_CASE_GLOB("V_MPEG4/ISO*") {
1796
0
            vars.p_fmt->i_codec = VLC_CODEC_MP4V;
1797
0
            fill_extra_data( vars.p_tk, 0 );
1798
0
        }
1799
35
        S_CASE("V_MPEGH/ISO/HEVC") {
1800
0
            vars.p_tk->fmt.i_codec = VLC_CODEC_HEVC;
1801
1802
0
            uint8_t* p_extra = (uint8_t*) vars.p_tk->p_extra_data;
1803
1804
            /* HACK: if we found invalid format, made by mkvmerge < 16.0.0,
1805
             *       we try to fix it. They fixed it in 16.0.0. */
1806
0
            const char* app = vars.obj->psz_writing_application;
1807
0
            if( p_extra && vars.p_tk->i_extra_data >= 3 &&
1808
0
                    p_extra[0] == 0 && (p_extra[1] != 0 || p_extra[2] > 1) )
1809
0
            {
1810
0
                msg_Warn(vars.p_demuxer,
1811
0
                        "Invalid HEVC reserved bits in mkv file "
1812
0
                        "made by %s, fixing it", app ? app : "unknown app");
1813
0
                p_extra[0] = 0x01;
1814
0
            }
1815
1816
0
            fill_extra_data( vars.p_tk, 0 );
1817
0
        }
1818
35
        S_CASE("V_QUICKTIME") {
1819
0
            ONLY_FMT(VIDEO);
1820
0
            if( vars.p_tk->i_extra_data > 4 )
1821
0
            {
1822
0
                MP4_Box_t *p_box = MP4_BoxNew(ATOM_root);
1823
0
                if( p_box )
1824
0
                {
1825
0
                    stream_t *p_mp4_stream = vlc_stream_MemoryNew( VLC_OBJECT(vars.p_demuxer),
1826
0
                                                                   vars.p_tk->p_extra_data,
1827
0
                                                                   vars.p_tk->i_extra_data,
1828
0
                                                                   true );
1829
0
                    if( p_mp4_stream )
1830
0
                    {
1831
0
                        p_box->i_type = GetFOURCC( vars.p_tk->p_extra_data );
1832
0
                        p_box->i_size = p_box->i_shortsize = vars.p_tk->i_extra_data;
1833
0
                        if( MP4_ReadBox_sample_vide( p_mp4_stream, p_box ) )
1834
0
                        {
1835
0
                            const MP4_Box_data_sample_vide_t *p_sample = p_box->data.p_sample_vide;
1836
0
                            vars.p_fmt->i_codec = p_box->i_type;
1837
0
                            if( p_sample->i_width && p_sample->i_height )
1838
0
                            {
1839
0
                                vars.p_tk->fmt.video.i_width = p_sample->i_width;
1840
0
                                vars.p_tk->fmt.video.i_height = p_sample->i_height;
1841
0
                            }
1842
0
                            vars.p_fmt->p_extra = malloc( p_sample->i_qt_image_description );
1843
0
                            if( vars.p_fmt->p_extra )
1844
0
                            {
1845
0
                                vars.p_fmt->i_extra = p_sample->i_qt_image_description;
1846
0
                                memcpy( vars.p_fmt->p_extra,
1847
0
                                        p_sample->p_qt_image_description, vars.p_fmt->i_extra );
1848
0
                            }
1849
0
                        }
1850
0
                        vlc_stream_Delete( p_mp4_stream );
1851
0
                    }
1852
0
                    MP4_BoxFree( p_box );
1853
0
                }
1854
0
            }
1855
0
            else throw std::runtime_error ("invalid extradata when handling V_QUICKTIME/*");
1856
0
        }
1857
35
        S_CASE("V_MJPEG") {
1858
0
            vars.p_fmt->i_codec = VLC_CODEC_MJPG;
1859
0
            vars.p_tk->b_pts_only = true;
1860
0
        }
1861
35
        S_CASE("V_UNCOMPRESSED") {
1862
0
            msg_Dbg( vars.p_demuxer, "uncompressed format detected");
1863
0
        }
1864
35
        S_CASE("V_FFV1") {
1865
0
            vars.p_fmt->i_codec = VLC_CODEC_FFV1;
1866
0
            fill_extra_data( vars.p_tk, 0 );
1867
0
        }
1868
35
        S_CASE("V_PRORES") {
1869
0
            vars.p_fmt->i_codec = VLC_CODEC_PRORES;
1870
0
            fill_extra_data( vars.p_tk, 0 );
1871
0
        }
1872
35
        S_CASE("A_MS/ACM") {
1873
0
            mkv_track_t * p_tk = vars.p_tk;
1874
0
            es_format_t * p_fmt = &vars.p_tk->fmt;
1875
1876
0
            if( p_tk->i_extra_data < (int)sizeof( WAVEFORMATEX ) )
1877
0
            {
1878
0
                msg_Err( vars.p_demuxer, "missing/invalid WAVEFORMATEX" );
1879
0
                p_tk->fmt.i_codec = VLC_CODEC_UNKNOWN;
1880
0
            }
1881
0
            else
1882
0
            {
1883
0
                ONLY_FMT(AUDIO);
1884
0
                WAVEFORMATEX *p_wf = (WAVEFORMATEX*)p_tk->p_extra_data;
1885
1886
0
                p_tk->fmt.audio.i_channels   = GetWLE( &p_wf->nChannels );
1887
0
                p_tk->fmt.audio.i_rate = GetDWLE( &p_wf->nSamplesPerSec );
1888
0
                p_tk->fmt.i_bitrate    = GetDWLE( &p_wf->nAvgBytesPerSec ) * 8;
1889
0
                p_tk->fmt.audio.i_blockalign = GetWLE( &p_wf->nBlockAlign );
1890
0
                p_tk->fmt.audio.i_bitspersample = GetWLE( &p_wf->wBitsPerSample );
1891
1892
0
                p_tk->fmt.i_extra            = GetWLE( &p_wf->cbSize );
1893
0
                if ( (size_t)p_tk->fmt.i_extra > p_tk->i_extra_data - sizeof( WAVEFORMATEX ) )
1894
0
                    p_tk->fmt.i_extra = 0;
1895
0
                if( p_tk->fmt.i_extra != 0 )
1896
0
                {
1897
0
                    p_tk->fmt.p_extra = xmalloc( p_tk->fmt.i_extra );
1898
0
                    if( p_tk->fmt.p_extra )
1899
0
                        memcpy( p_tk->fmt.p_extra, &p_wf[1], p_tk->fmt.i_extra );
1900
0
                    else
1901
0
                        p_tk->fmt.i_extra = 0;
1902
0
                }
1903
1904
0
                if( p_wf->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
1905
0
                    p_tk->i_extra_data >= sizeof(WAVEFORMATEXTENSIBLE) )
1906
0
                {
1907
0
                    WAVEFORMATEXTENSIBLE *p_wext = container_of(p_wf, WAVEFORMATEXTENSIBLE, Format);
1908
0
                    GUID subFormat = p_wext->SubFormat;
1909
1910
0
                    sf_tag_to_fourcc( &subFormat,  &p_tk->fmt.i_codec, NULL);
1911
                    /* FIXME should we use Samples */
1912
1913
0
                    if( p_tk->fmt.audio.i_channels > 2 &&
1914
0
                        ( p_tk->fmt.i_codec != VLC_CODEC_UNKNOWN ) )
1915
0
                    {
1916
0
                        uint32_t wfextcm = GetDWLE( &p_wext->dwChannelMask );
1917
0
                        int match;
1918
0
                        unsigned i_channel_mask = getChannelMask( &wfextcm,
1919
0
                                                                  p_tk->fmt.audio.i_channels,
1920
0
                                                                  &match );
1921
0
                        p_tk->fmt.i_codec = vlc_fourcc_GetCodecAudio( p_tk->fmt.i_codec,
1922
0
                                                                      p_tk->fmt.audio.i_bitspersample );
1923
0
                        if( i_channel_mask )
1924
0
                        {
1925
0
                            p_tk->i_chans_to_reorder = aout_CheckChannelReorder(
1926
0
                                pi_channels_aout, NULL,
1927
0
                                i_channel_mask,
1928
0
                                p_tk->pi_chan_table );
1929
1930
0
                            p_tk->fmt.audio.i_physical_channels = i_channel_mask;
1931
0
                        }
1932
0
                    }
1933
0
                }
1934
0
                else
1935
0
                {
1936
0
                    wf_tag_to_fourcc( GetWLE( &p_wf->wFormatTag ), &p_tk->fmt.i_codec, NULL );
1937
0
                    if( p_wf->wFormatTag == WAVE_FORMAT_AAC_LATM )
1938
0
                    {
1939
0
                        p_tk->fmt.i_original_fourcc = VLC_FOURCC('L','A','T','M');
1940
0
                    }
1941
0
                    else if( p_wf->wFormatTag == WAVE_FORMAT_AAC_ADTS )
1942
0
                    {
1943
0
                        p_tk->fmt.i_original_fourcc = VLC_FOURCC('A','D','T','S');
1944
0
                    }
1945
0
                }
1946
1947
0
                if( p_tk->fmt.i_codec == VLC_CODEC_UNKNOWN )
1948
0
                    msg_Err( vars.p_demuxer, "Unrecognized wf tag: 0x%x", GetWLE( &p_wf->wFormatTag ) );
1949
0
            }
1950
0
            p_fmt->b_packetized = !p_fmt->audio.i_blockalign;
1951
0
        }
1952
35
        static void A_MPEG_helper_ (HandlerPayload& vars) {
1953
0
            vars.p_tk->fmt.i_codec = VLC_CODEC_MPGA;
1954
0
            vars.p_fmt->b_packetized = false;
1955
0
        }
1956
35
        S_CASE("A_MPEG/L3") { A_MPEG_helper_(vars); }
1957
35
        S_CASE("A_MPEG/L2") { A_MPEG_helper_(vars); }
1958
35
        S_CASE("A_MPEG/L1") { A_MPEG_helper_(vars); }
1959
35
        S_CASE("A_AC3") {
1960
0
            ONLY_FMT(AUDIO);
1961
            // the AC-3 default duration cannot be trusted, see #8512
1962
0
            if ( vars.p_tk->fmt.audio.i_rate == 8000 )
1963
0
            {
1964
0
                vars.p_tk->b_no_duration = true;
1965
0
                vars.p_tk->i_default_duration = 0;
1966
0
            }
1967
1968
0
            vars.p_fmt->i_codec = VLC_CODEC_A52;
1969
0
            vars.p_fmt->b_packetized = false;
1970
0
        }
1971
35
        S_CASE("A_ATRAC/AT1") {
1972
0
            ONLY_FMT(AUDIO);
1973
0
            vars.p_fmt->i_codec = VLC_CODEC_ATRAC1;
1974
0
            vars.p_tk->fmt.audio.i_blockalign = vars.p_tk->fmt.audio.i_channels * 212;
1975
0
        }
1976
35
        S_CASE("A_EAC3") {
1977
0
            vars.p_fmt->i_codec = VLC_CODEC_EAC3;
1978
0
            vars.p_fmt->b_packetized = false;
1979
0
        }
1980
35
        S_CASE("A_DTS")  {
1981
0
            vars.p_fmt->i_codec = VLC_CODEC_DTS;
1982
0
            vars.p_fmt->b_packetized = false;
1983
0
        }
1984
35
        S_CASE("A_MLP")  { vars.p_fmt->i_codec = VLC_CODEC_MLP; }
1985
35
        S_CASE("A_TRUEHD") { /* FIXME when more samples arrive */
1986
0
            vars.p_fmt->i_codec = VLC_CODEC_TRUEHD;
1987
0
            vars.p_fmt->b_packetized = false;
1988
0
        }
1989
35
        S_CASE("A_FLAC") {
1990
4
            vars.p_fmt->i_codec = VLC_CODEC_FLAC;
1991
4
            fill_extra_data( vars.p_tk, 0 );
1992
4
        }
1993
35
        S_CASE("A_VORBIS") {
1994
2
            vars.p_fmt->i_codec = VLC_CODEC_VORBIS;
1995
2
            fill_extra_data( vars.p_tk, 0 );
1996
2
        }
1997
35
        static void A_OPUS__helper(HandlerPayload& vars) {
1998
0
            ONLY_FMT(AUDIO);
1999
0
            vars.p_fmt->i_codec = VLC_CODEC_OPUS;
2000
0
            vars.p_tk->b_no_duration = true;
2001
0
            if( !vars.p_tk->fmt.audio.i_rate )
2002
0
            {
2003
0
                msg_Err( vars.p_demuxer,"No sampling rate, defaulting to 48kHz");
2004
0
                vars.p_fmt->audio.i_rate = 48000;
2005
0
            }
2006
0
            const uint8_t tags[16] = {'O','p','u','s','T','a','g','s',
2007
0
                                       0, 0, 0, 0, 0, 0, 0, 0};
2008
0
            size_t ps[2] = { vars.p_tk->i_extra_data, 16 };
2009
0
            const void *pkt[2] = { static_cast<const void *>( vars.p_tk->p_extra_data ),
2010
0
                                   static_cast<const void *>( tags ) };
2011
2012
0
            if( xiph_PackHeaders( &vars.p_fmt->i_extra,
2013
0
                &vars.p_fmt->p_extra,
2014
0
                ps, pkt, 2 ) )
2015
0
                msg_Err( vars.p_demuxer, "Couldn't pack OPUS headers");
2016
0
        }
2017
35
        S_CASE("A_OPUS")                { A_OPUS__helper( vars ); }
2018
35
        S_CASE("A_OPUS/EXPERIMENTAL")   { A_OPUS__helper( vars ); }
2019
35
        static void A_AAC_MPEG__helper(HandlerPayload& vars, int i_profile, bool sbr = false) {
2020
0
            ONLY_FMT(AUDIO);
2021
0
            int i_srate;
2022
2023
0
            mkv_track_t * p_tk = vars.p_tk;
2024
2025
0
            static const unsigned int i_sample_rates[] =
2026
0
            {
2027
0
                96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050,
2028
0
                16000, 12000, 11025,  8000,  7350,     0,     0,     0
2029
0
            };
2030
2031
0
            p_tk->fmt.i_codec = VLC_CODEC_MP4A;
2032
2033
0
            for( i_srate = 0; i_srate < 13; i_srate++ )
2034
0
            {
2035
0
                if( i_sample_rates[i_srate] == p_tk->i_original_rate )
2036
0
                    break;
2037
0
            }
2038
2039
0
            msg_Dbg (vars.p_demuxer, "profile=%d srate=%d", i_profile, i_srate );
2040
2041
0
            p_tk->fmt.i_extra = sbr ? 5 : 2;
2042
0
            p_tk->fmt.p_extra = xmalloc( p_tk->fmt.i_extra );
2043
0
            ((uint8_t*)p_tk->fmt.p_extra)[0] = ((i_profile + 1) << 3) | ((i_srate&0xe) >> 1);
2044
0
            ((uint8_t*)p_tk->fmt.p_extra)[1] = ((i_srate & 0x1) << 7) | (p_tk->fmt.audio.i_channels << 3);
2045
2046
0
            if (sbr) {
2047
0
                int syncExtensionType = 0x2B7;
2048
0
                int iDSRI;
2049
0
                for (iDSRI=0; iDSRI<13; iDSRI++)
2050
0
                    if( i_sample_rates[iDSRI] == p_tk->fmt.audio.i_rate )
2051
0
                        break;
2052
0
                ((uint8_t*)p_tk->fmt.p_extra)[2] = (syncExtensionType >> 3) & 0xFF;
2053
0
                ((uint8_t*)p_tk->fmt.p_extra)[3] = ((syncExtensionType & 0x7) << 5) | 5;
2054
0
                ((uint8_t*)p_tk->fmt.p_extra)[4] = ((1 & 0x1) << 7) | (iDSRI << 3);
2055
0
            }
2056
2057
0
        }
2058
35
        S_CASE("A_AAC/MPEG2/MAIN")   { A_AAC_MPEG__helper( vars, 0 ); }
2059
35
        S_CASE("A_AAC/MPEG4/MAIN")   { A_AAC_MPEG__helper( vars, 0 ); }
2060
35
        S_CASE("A_AAC/MPEG2/LC")     { A_AAC_MPEG__helper( vars, 1 ); }
2061
35
        S_CASE("A_AAC/MPEG4/LC")     { A_AAC_MPEG__helper( vars, 1 ); }
2062
35
        S_CASE("A_AAC/MPEG2/SSR")    { A_AAC_MPEG__helper( vars, 2 ); }
2063
35
        S_CASE("A_AAC/MPEG4/SSR")    { A_AAC_MPEG__helper( vars, 2 ); }
2064
35
        S_CASE("A_AAC/MPEG4/LTP")    { A_AAC_MPEG__helper( vars, 3 ); }
2065
35
        S_CASE("A_AAC/MPEG2/LC/SBR") { A_AAC_MPEG__helper( vars, 1, true ); }
2066
35
        S_CASE("A_AAC/MPEG4/LC/SBR") { A_AAC_MPEG__helper( vars, 1, true ); }
2067
35
        S_CASE("A_AAC/MPEG4/") { A_AAC_MPEG__helper( vars, 3 ); } // see #4250
2068
35
        S_CASE("A_AAC/MPEG2/") { A_AAC_MPEG__helper( vars, 3 ); } // backward compatibility
2069
35
        S_CASE("A_AAC") {
2070
5
            vars.p_tk->fmt.i_codec = VLC_CODEC_MP4A;
2071
5
            fill_extra_data( vars.p_tk, 0 );
2072
5
        }
2073
35
        S_CASE("A_ALAC") {
2074
0
            vars.p_tk->fmt.i_codec = VLC_CODEC_ALAC;
2075
0
            fill_extra_data_alac( vars.p_tk );
2076
0
        }
2077
35
        S_CASE("A_WAVPACK4") {
2078
0
            vars.p_tk->fmt.i_codec = VLC_CODEC_WAVPACK;
2079
0
            fill_extra_data( vars.p_tk, 0);
2080
0
        }
2081
35
        S_CASE("A_TTA1") {
2082
0
            ONLY_FMT(AUDIO);
2083
0
            mkv_track_t * p_tk  = vars.p_tk;
2084
0
            es_format_t * p_fmt = vars.p_fmt;
2085
2086
0
            p_fmt->i_codec = VLC_CODEC_TTA;
2087
0
            if( p_tk->i_extra_data > 0 )
2088
0
            {
2089
0
                fill_extra_data( p_tk, 0 );
2090
0
            }
2091
0
            else
2092
0
            {
2093
0
                p_fmt->i_extra = 30;
2094
0
                p_fmt->p_extra = xmalloc( p_fmt->i_extra );
2095
0
                uint8_t *p_extra = (uint8_t*)p_fmt->p_extra;
2096
0
                memcpy( &p_extra[ 0], "TTA1", 4 );
2097
0
                SetWLE( &p_extra[ 4], 1 );
2098
0
                SetWLE( &p_extra[ 6], p_fmt->audio.i_channels );
2099
0
                SetWLE( &p_extra[ 8], p_fmt->audio.i_bitspersample );
2100
0
                SetDWLE( &p_extra[10], p_fmt->audio.i_rate );
2101
0
                SetDWLE( &p_extra[14], 0xffffffff );
2102
0
                memset( &p_extra[18], 0, 30  - 18 );
2103
0
            }
2104
0
        }
2105
35
        static void A_PCM__helper (HandlerPayload& vars, uint32_t i_codec) {
2106
0
            ONLY_FMT(AUDIO);
2107
0
            vars.p_fmt->i_codec = i_codec;
2108
0
            vars.p_fmt->audio.i_blockalign = ( vars.p_fmt->audio.i_bitspersample + 7 ) / 8 * vars.p_fmt->audio.i_channels;
2109
2110
0
        }
2111
35
        S_CASE("A_PCM/INT/BIG")    { A_PCM__helper ( vars, VLC_FOURCC( 't','w','o','s' ) ); }
2112
35
        S_CASE("A_PCM/INT/LIT")    { A_PCM__helper ( vars, VLC_FOURCC( 'a','r','a','w' ) ); }
2113
35
        S_CASE("A_PCM/FLOAT/IEEE") { A_PCM__helper ( vars, VLC_FOURCC( 'a','f','l','t' ) ) ;}
2114
35
        S_CASE("A_REAL/14_4") {
2115
0
            ONLY_FMT(AUDIO);
2116
0
            vars.p_fmt->i_codec = VLC_CODEC_RA_144;
2117
0
            vars.p_fmt->audio.i_channels = 1;
2118
0
            vars.p_fmt->audio.i_rate = 8000;
2119
0
            vars.p_fmt->audio.i_blockalign = 0x14;
2120
0
        }
2121
35
        static bool A_REAL__is_valid (HandlerPayload& vars) {
2122
0
            ONLY_FMT(AUDIO);
2123
0
            uint8_t *p = vars.p_tk->p_extra_data;
2124
2125
0
            if (vars.p_tk->i_extra_data <= sizeof(real_audio_private))
2126
0
                return false;
2127
2128
0
            if( memcmp( p, ".ra", 3 ) ) {
2129
0
                msg_Err( vars.p_demuxer, "Invalid Real ExtraData 0x%4.4s", (char *)p );
2130
0
                vars.p_tk->fmt.i_codec = VLC_CODEC_UNKNOWN;
2131
0
                return false;
2132
0
            }
2133
2134
0
            return true;
2135
0
        }
2136
35
        static void A_REAL__helper (HandlerPayload& vars, uint32_t i_codec) {
2137
0
            mkv_track_t        * p_tk = vars.p_tk;
2138
0
            real_audio_private * priv = (real_audio_private*) p_tk->p_extra_data;
2139
2140
0
            p_tk->fmt.i_codec = i_codec;
2141
2142
            /* FIXME RALF and SIPR */
2143
0
            uint16_t version = (uint16_t) hton16(priv->version);
2144
2145
0
            p_tk->p_sys = new Cook_PrivateTrackData(
2146
0
                  hton16( priv->sub_packet_h ),
2147
0
                  hton16( priv->frame_size ),
2148
0
                  hton16( priv->sub_packet_size )
2149
0
            );
2150
2151
0
            if( unlikely( !p_tk->p_sys ) )
2152
0
                throw std::runtime_error ("p_tk->p_sys is NULL when handling A_REAL/28_8");
2153
2154
0
            if( unlikely( p_tk->p_sys->Init() ) )
2155
0
                throw std::runtime_error ("p_tk->p_sys->Init() failed when handling A_REAL/28_8");
2156
2157
0
            if( version == 4 )
2158
0
            {
2159
0
                real_audio_private_v4 * v4 = (real_audio_private_v4*) priv;
2160
0
                p_tk->fmt.audio.i_channels = hton16(v4->channels);
2161
0
                p_tk->fmt.audio.i_bitspersample = hton16(v4->sample_size);
2162
0
                p_tk->fmt.audio.i_rate = hton16(v4->sample_rate);
2163
0
            }
2164
0
            else if( version == 5 )
2165
0
            {
2166
0
                real_audio_private_v5 * v5 = (real_audio_private_v5*) priv;
2167
0
                p_tk->fmt.audio.i_channels = hton16(v5->channels);
2168
0
                p_tk->fmt.audio.i_bitspersample = hton16(v5->sample_size);
2169
0
                p_tk->fmt.audio.i_rate = hton16(v5->sample_rate);
2170
0
            }
2171
0
            msg_Dbg(vars.p_demuxer, "%d channels %d bits %d Hz",p_tk->fmt.audio.i_channels, p_tk->fmt.audio.i_bitspersample, p_tk->fmt.audio.i_rate);
2172
2173
0
            fill_extra_data( p_tk, p_tk->fmt.i_codec == VLC_CODEC_RA_288 ? 0 : 78);
2174
0
        }
2175
35
        S_CASE("A_REAL/COOK") {
2176
0
            if (!A_REAL__is_valid (vars))
2177
0
                return;
2178
2179
0
            real_audio_private * priv = (real_audio_private*) vars.p_tk->p_extra_data;
2180
0
            vars.p_tk->fmt.audio.i_blockalign = hton16(priv->sub_packet_size);
2181
2182
0
            A_REAL__helper (vars, VLC_CODEC_COOK);
2183
0
        }
2184
35
        S_CASE("A_REAL/ATRC") {
2185
0
            if (!A_REAL__is_valid (vars))
2186
0
                return;
2187
2188
0
            real_audio_private * priv = (real_audio_private*) vars.p_tk->p_extra_data;
2189
0
            vars.p_tk->fmt.audio.i_blockalign = hton16(priv->sub_packet_size);
2190
2191
0
            A_REAL__helper (vars, VLC_CODEC_ATRAC3);
2192
0
        }
2193
35
        S_CASE("A_REAL/28_8") {
2194
0
            if (!A_REAL__is_valid (vars))
2195
0
                return;
2196
2197
0
            A_REAL__helper (vars, VLC_CODEC_RA_288);
2198
0
        }
2199
35
        S_CASE("A_QUICKTIME/QDM2") {
2200
0
            vars.p_fmt->i_cat   = AUDIO_ES;
2201
0
            vars.p_fmt->i_codec = VLC_CODEC_QDM2;
2202
2203
0
            fill_extra_data( vars.p_tk, 0 );
2204
0
        }
2205
35
        S_CASE("A_QUICKTIME/QDMC") {
2206
0
            vars.p_fmt->i_cat   = AUDIO_ES;
2207
0
            vars.p_fmt->i_codec = VLC_CODEC_QDMC;
2208
2209
0
            fill_extra_data( vars.p_tk, 0 );
2210
0
        }
2211
35
        S_CASE_GLOB("A_QUICKTIME/*") {
2212
0
            if (vars.p_tk->i_extra_data < 4)
2213
0
                throw std::runtime_error ("invalid extradata when handling A_QUICKTIME/*");
2214
2215
0
            vars.p_fmt->i_cat = AUDIO_ES;
2216
0
            vars.p_fmt->i_codec = GetFOURCC(vars.p_tk->p_extra_data);
2217
2218
0
            fill_extra_data( vars.p_tk, 0 );
2219
0
        }
2220
35
        S_CASE("S_KATE") {
2221
0
            ONLY_FMT(SPU);
2222
0
            vars.p_fmt->i_codec = VLC_CODEC_KATE;
2223
0
            vars.p_fmt->subs.psz_encoding = strdup( "UTF-8" );
2224
2225
0
            fill_extra_data( vars.p_tk, 0 );
2226
0
        }
2227
35
        S_CASE("S_TEXT/ASCII") {
2228
0
            ONLY_FMT(SPU);
2229
0
            vars.p_fmt->i_codec = VLC_CODEC_SUBT;
2230
0
            vars.p_fmt->subs.psz_encoding = strdup( "ASCII" );
2231
0
        }
2232
35
        S_CASE("S_TEXT/UTF8") {
2233
8
            ONLY_FMT(SPU);
2234
8
            vars.p_tk->fmt.i_codec = VLC_CODEC_SUBT;
2235
8
            vars.p_tk->fmt.subs.psz_encoding = strdup( "UTF-8" );
2236
8
        }
2237
35
        S_CASE("S_TEXT/USF") {
2238
0
            ONLY_FMT(SPU);
2239
0
            vars.p_tk->fmt.i_codec = VLC_CODEC_USF;
2240
0
            vars.p_tk->fmt.subs.psz_encoding = strdup( "UTF-8" );
2241
0
            fill_extra_data( vars.p_tk, 0 );
2242
0
        }
2243
35
        static void SSA__helper (HandlerPayload& vars) {
2244
0
            ONLY_FMT(SPU);
2245
0
            vars.p_tk->fmt.i_codec = VLC_CODEC_SSA;
2246
0
            vars.p_tk->fmt.subs.psz_encoding = strdup( "UTF-8" );
2247
0
            fill_extra_data( vars.p_tk, 0 );
2248
0
        }
2249
35
        S_CASE("S_TEXT/SSA") { SSA__helper( vars ); }
2250
35
        S_CASE("S_TEXT/ASS") { SSA__helper( vars ); }
2251
35
        S_CASE("S_SSA")      { SSA__helper( vars ); }
2252
35
        S_CASE("S_ASS")      { SSA__helper( vars ); }
2253
35
        S_CASE("S_VOBSUB") {
2254
0
            ONLY_FMT(SPU);
2255
0
            mkv_track_t * p_tk = vars.p_tk;
2256
2257
0
            p_tk->fmt.i_codec = VLC_CODEC_SPU;
2258
0
            p_tk->b_no_duration = true;
2259
0
            if( likely( p_tk->i_extra_data && p_tk->fmt.i_cat == SPU_ES ) )
2260
0
            {
2261
0
                vobsub_extra_parse( VLC_OBJECT(vars.p_demuxer), &p_tk->fmt.subs,
2262
0
                                    p_tk->p_extra_data, p_tk->i_extra_data );
2263
0
            }
2264
0
        }
2265
35
        S_CASE("S_DVBSUB")
2266
35
        {
2267
0
            ONLY_FMT(SPU);
2268
0
            vars.p_fmt->i_codec = VLC_CODEC_DVBS;
2269
2270
0
            if( vars.p_tk->i_extra_data < 4 )
2271
0
                throw std::runtime_error( "not enough codec data for S_DVBSUB" );
2272
2273
0
            uint16_t page_id = GetWBE( &vars.p_tk->p_extra_data[0] );
2274
0
            uint16_t ancillary_id = GetWBE( &vars.p_tk->p_extra_data[2] );
2275
2276
0
            vars.p_fmt->subs.dvb.i_id = ( ancillary_id << 16 ) | page_id;
2277
0
        }
2278
35
        S_CASE("S_HDMV/PGS") {
2279
0
            vars.p_fmt->i_codec = VLC_CODEC_BD_PG;
2280
0
        }
2281
35
        S_CASE("S_HDMV/TEXTST") {
2282
0
            vars.p_fmt->i_codec = VLC_CODEC_BD_TEXT;
2283
0
        }
2284
35
        S_CASE("D_WEBVTT/SUBTITLES") {
2285
0
            ONLY_FMT(SPU);
2286
0
            vars.p_fmt->i_codec = VLC_CODEC_WEBVTT;
2287
0
            vars.p_fmt->subs.psz_encoding = strdup( "UTF-8");
2288
0
        }
2289
35
        S_CASE("S_TEXT/WEBVTT") {
2290
0
            ONLY_FMT(SPU);
2291
0
            vars.p_fmt->i_codec = VLC_CODEC_WEBVTT;
2292
0
            vars.p_fmt->subs.psz_encoding = strdup( "UTF-8");
2293
0
            fill_extra_data( vars.p_tk, 0 );
2294
0
        }
2295
35
        S_CASE("B_VOBBTN") {
2296
0
            vars.p_fmt->i_cat = DATA_ES;
2297
0
        }
2298
35
        S_CASE_DEFAULT(str) {
2299
0
            msg_Err( vars.p_demuxer, "unknown codec id=`%s'", str );
2300
0
            vars.p_tk->fmt.i_codec = VLC_CODEC_UNKNOWN;
2301
0
        }
2302
35
    };
2303
2304
35
    try {
2305
35
        TrackCodecHandlers::Dispatcher().send( p_tk->codec.c_str(), &captures );
2306
35
    }
2307
35
    catch (std::exception const& e)
2308
35
    {
2309
0
        msg_Err( &sys.demuxer, "Error when trying to initiate track (codec: %s): %s",
2310
0
          p_tk->codec.c_str(), e.what () );
2311
0
        return false;
2312
0
    }
2313
2314
35
    return true;
2315
35
}
2316
2317
} // namespace