Coverage Report

Created: 2025-08-29 07:30

/src/vlc/modules/demux/mkv/matroska_segment.cpp
Line
Count
Source (jump to first uncovered line)
1
/*****************************************************************************
2
 * matroska_segment.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
24
#include "matroska_segment.hpp"
25
#include "chapters.hpp"
26
#include "demux.hpp"
27
#include "util.hpp"
28
#include "Ebml_dispatcher.hpp"
29
30
#include <vlc_arrays.h>
31
32
#include <new>
33
#include <iterator>
34
#include <limits>
35
36
namespace mkv {
37
38
matroska_segment_c::matroska_segment_c( demux_sys_t & demuxer, matroska_iostream_c & estream, KaxSegment *p_seg )
39
17
    :segment(p_seg)
40
17
    ,es(estream)
41
17
    ,i_timescale(MKVD_TIMECODESCALE)
42
17
    ,i_duration(-1)
43
17
    ,i_mk_start_time(0)
44
17
    ,i_seekhead_count(0)
45
17
    ,i_seekhead_position(-1)
46
17
    ,i_cues_position(-1)
47
17
    ,i_tracks_position(-1)
48
17
    ,i_info_position(-1)
49
17
    ,i_chapters_position(-1)
50
17
    ,i_attachments_position(-1)
51
    ,cluster(NULL)
52
17
    ,i_block_pos(0)
53
    ,p_segment_uid(NULL)
54
    ,p_prev_segment_uid(NULL)
55
    ,p_next_segment_uid(NULL)
56
17
    ,b_cues(false)
57
    ,psz_muxing_application(NULL)
58
    ,psz_writing_application(NULL)
59
    ,psz_segment_filename(NULL)
60
    ,psz_title(NULL)
61
    ,psz_date_utc(NULL)
62
17
    ,i_default_edition(0)
63
17
    ,sys(demuxer)
64
17
    ,ep( EbmlParser(&estream, p_seg, &demuxer.demuxer ))
65
17
    ,b_preloaded(false)
66
17
    ,b_ref_external_segments(false)
67
17
{
68
17
}
69
70
matroska_segment_c::~matroska_segment_c()
71
17
{
72
17
    free( psz_writing_application );
73
17
    free( psz_muxing_application );
74
17
    free( psz_segment_filename );
75
17
    free( psz_title );
76
17
    free( psz_date_utc );
77
78
17
    delete segment;
79
17
    delete p_segment_uid;
80
17
    delete p_prev_segment_uid;
81
17
    delete p_next_segment_uid;
82
83
17
    vlc_delete_all( stored_editions );
84
17
    vlc_delete_all( translations );
85
17
    vlc_delete_all( families );
86
17
}
87
88
89
/*****************************************************************************
90
 * Tools                                                                     *
91
 *****************************************************************************
92
 *  * LoadCues : load the cues element and update index
93
 *  * LoadTags : load ... the tags element
94
 *  * InformationCreate : create all information, load tags if present
95
 *****************************************************************************/
96
void matroska_segment_c::LoadCues( KaxCues *cues )
97
4
{
98
4
    EbmlElement *el;
99
100
4
    if( b_cues )
101
0
    {
102
0
        msg_Warn( &sys.demuxer, "There can be only 1 Cues per section." );
103
0
        return;
104
0
    }
105
106
4
    EbmlParser eparser (&es, cues, &sys.demuxer );
107
176
    while( ( el = eparser.Get() ) != NULL )
108
172
    {
109
172
        if( MKV_IS_ID( el, KaxCuePoint ) )
110
168
        {
111
168
            uint64_t cue_position = -1;
112
168
            vlc_tick_t  cue_mk_time = -1;
113
114
168
            unsigned int track_id = 0;
115
168
            bool b_invalid_cue = false;
116
117
168
            eparser.Down();
118
504
            while( ( el = eparser.Get() ) != NULL )
119
336
            {
120
336
                if ( MKV_CHECKED_PTR_DECL( cuetime, KaxCueTime, el ) )
121
168
                {
122
168
                    try
123
168
                    {
124
168
                        if( unlikely( !cuetime->ValidateSize() ) )
125
0
                        {
126
0
                            msg_Err( &sys.demuxer, "CueTime size too big");
127
0
                            b_invalid_cue = true;
128
0
                            break;
129
0
                        }
130
168
                        cuetime->ReadData( es.I_O() );
131
168
                    }
132
168
                    catch(...)
133
168
                    {
134
0
                        msg_Err( &sys.demuxer, "Error while reading CueTime" );
135
0
                        b_invalid_cue = true;
136
0
                        break;
137
0
                    }
138
168
                    cue_mk_time = VLC_TICK_FROM_NS(static_cast<uint64_t>( *cuetime ) * i_timescale);
139
168
                }
140
168
                else if( MKV_IS_ID( el, KaxCueTrackPositions ) )
141
168
                {
142
168
                    eparser.Down();
143
168
                    try
144
168
                    {
145
504
                        while( ( el = eparser.Get() ) != NULL )
146
336
                        {
147
336
                            if( unlikely( !el->ValidateSize() ) )
148
0
                            {
149
0
                                eparser.Up();
150
0
                                msg_Err( &sys.demuxer, "Error %s too big, aborting", EBML_NAME(el) );
151
0
                                b_invalid_cue = true;
152
0
                                break;
153
0
                            }
154
155
336
                            if( MKV_CHECKED_PTR_DECL ( kct_ptr, KaxCueTrack, el ) )
156
168
                            {
157
168
                                kct_ptr->ReadData( es.I_O() );
158
168
                                track_id = static_cast<uint16_t>( *kct_ptr );
159
168
                            }
160
168
                            else if( MKV_CHECKED_PTR_DECL ( kccp_ptr, KaxCueClusterPosition, el ) )
161
168
                            {
162
168
                                kccp_ptr->ReadData( es.I_O() );
163
168
                                cue_position = segment->GetGlobalPosition( static_cast<uint64_t>( *kccp_ptr ) );
164
165
168
                                _seeker.add_cluster_position( cue_position );
166
168
                            }
167
0
                            else if( MKV_CHECKED_PTR_DECL ( kcbn_ptr, KaxCueBlockNumber, el ) )
168
0
                            {
169
0
                                VLC_UNUSED( kcbn_ptr );
170
0
                            }
171
0
#if LIBMATROSKA_VERSION >= 0x010401
172
0
                            else if( MKV_CHECKED_PTR_DECL( cuerelative, KaxCueRelativePosition, el ) )
173
0
                            {
174
                                // IGNORE
175
0
                                cuerelative->ReadData( es.I_O() );
176
0
                            }
177
0
                            else if( MKV_CHECKED_PTR_DECL( cueblock, KaxCueBlockNumber, el ) )
178
0
                            {
179
                                // IGNORE
180
0
                                cueblock->ReadData( es.I_O() );
181
0
                            }
182
0
                            else if( MKV_CHECKED_PTR_DECL( cueref, KaxCueReference, el ) )
183
0
                            {
184
                                // IGNORE
185
0
                                cueref->ReadData( es.I_O(), SCOPE_ALL_DATA );
186
0
                            }
187
0
                            else if( MKV_CHECKED_PTR_DECL( cueduration, KaxCueDuration, el ) )
188
0
                            {
189
                                /* For future use */
190
0
                                cueduration->ReadData( es.I_O() );
191
0
                            }
192
0
#endif
193
0
                            else
194
0
                            {
195
0
                                msg_Dbg( &sys.demuxer, "         * Unknown (%s)", EBML_NAME(el) );
196
0
                            }
197
336
                        }
198
168
                    }
199
168
                    catch(...)
200
168
                    {
201
0
                        eparser.Up();
202
0
                        msg_Err( &sys.demuxer, "Error while reading %s", EBML_NAME(el) );
203
0
                        b_invalid_cue = true;
204
0
                        break;
205
0
                    }
206
168
                    eparser.Up();
207
168
                }
208
0
                else
209
0
                {
210
0
                    msg_Dbg( &sys.demuxer, "     * Unknown (%s)", EBML_NAME(el) );
211
0
                }
212
336
            }
213
168
            eparser.Up();
214
215
168
            if( track_id != 0 && cue_mk_time != -1 && cue_position != static_cast<uint64_t>( -1 ) ) {
216
217
168
                SegmentSeeker::Seekpoint::TrustLevel level = SegmentSeeker::Seekpoint::DISABLED;
218
219
168
                if( ! b_invalid_cue && tracks.find( track_id ) != tracks.end() )
220
168
                {
221
168
                    level = sys.trust_cues ?
222
0
                            SegmentSeeker::Seekpoint::TRUSTED :
223
168
                            SegmentSeeker::Seekpoint::QUESTIONABLE;
224
168
                }
225
226
168
                _seeker.add_seekpoint( track_id,
227
168
                    SegmentSeeker::Seekpoint( cue_position, cue_mk_time, level ) );
228
168
            }
229
168
        }
230
4
        else
231
4
        {
232
4
            msg_Dbg( &sys.demuxer, " * Unknown (%s)", EBML_NAME(el) );
233
4
        }
234
172
    }
235
4
    b_cues = true;
236
4
    msg_Dbg( &sys.demuxer, "|   - loading cues done." );
237
4
}
238
239
240
static const struct {
241
    vlc_meta_type_t type;
242
    const char *key;
243
    int target_type; /* 0 is valid for all target_type */
244
} metadata_map[] = {
245
                     {vlc_meta_ShowName,    "TITLE",         70},
246
                     {vlc_meta_Album,       "TITLE",         50},
247
                     {vlc_meta_Title,       "TITLE",         30},
248
                     {vlc_meta_DiscNumber,  "PART_NUMBER",   60},
249
                     {vlc_meta_Season,      "PART_NUMBER",   60},
250
                     {vlc_meta_Episode,     "PART_NUMBER",   50},
251
                     {vlc_meta_TrackNumber, "PART_NUMBER",   30},
252
                     {vlc_meta_DiscTotal,   "TOTAL_PARTS",   70},
253
                     {vlc_meta_TrackTotal,  "TOTAL_PARTS",   30},
254
                     {vlc_meta_Setting,     "ENCODER_SETTINGS", 0},
255
                     /* TODO read TagLanguage {vlc_meta_Language} */
256
                     /* TODO read tags targeting attachments {vlc_meta_ArtworkURL, */
257
                     {vlc_meta_AlbumArtist, "ARTIST",        50},
258
                     {vlc_meta_Artist,      "ARTIST",        0},
259
                     {vlc_meta_Director,    "DIRECTOR",      0},
260
                     {vlc_meta_Actors,      "ACTOR",         0},
261
                     {vlc_meta_Genre,       "GENRE",         0},
262
                     {vlc_meta_Copyright,   "COPYRIGHT",     0},
263
                     {vlc_meta_Description, "DESCRIPTION",   0},
264
                     {vlc_meta_Description, "COMMENT",       0},
265
                     {vlc_meta_Rating,      "RATING",        0},
266
                     {vlc_meta_Date,        "DATE_RELEASED", 0},
267
                     {vlc_meta_Date,        "DATE_RELEASE",  0},
268
                     {vlc_meta_Date,        "DATE_RECORDED", 0},
269
                     {vlc_meta_URL,         "URL",           0},
270
                     {vlc_meta_Publisher,   "PUBLISHER",     0},
271
                     {vlc_meta_EncodedBy,   "ENCODED_BY",    0},
272
                     {vlc_meta_Album,       "ALBUM",         0}, /* invalid tag */
273
                     {vlc_meta_Title,       NULL,            0},
274
};
275
276
bool matroska_segment_c::ParseSimpleTags( SimpleTag* pout_simple, KaxTagSimple *tag, int target_type )
277
28
{
278
28
    msg_Dbg( &sys.demuxer, "|   + Simple Tag ");
279
28
    struct SimpleTagHandlerPayload
280
28
    {
281
28
        matroska_segment_c * const obj;
282
28
        EbmlParser         * const ep;
283
28
        demux_sys_t        & sys;
284
28
        SimpleTag          & out;
285
28
        int                target_type;
286
28
    } payload = { this, &ep, sys, *pout_simple, 50 };
287
28
    MKV_SWITCH_CREATE( EbmlTypeDispatcher, SimpleTagHandler, SimpleTagHandlerPayload )
288
28
    {
289
28
        MKV_SWITCH_INIT();
290
28
        E_CASE( KaxTagName, entry )
291
28
        {
292
28
            vars.out.tag_name = UTFstring( entry ).GetUTF8().c_str();
293
28
        }
294
28
        E_CASE( KaxTagString, entry )
295
28
        {
296
28
            vars.out.value = UTFstring( entry ).GetUTF8().c_str();
297
28
        }
298
28
        E_CASE( KaxTagLangue, entry )
299
28
        {
300
0
            vars.out.lang = entry.GetValue();
301
0
        }
302
28
        E_CASE( KaxTagDefault, unused )
303
28
        {
304
0
            VLC_UNUSED(unused);
305
0
            VLC_UNUSED(vars);
306
0
        }
307
28
        E_CASE( KaxTagSimple, simple )
308
28
        {
309
0
            SimpleTag st; // ParseSimpleTags will write to this variable
310
                          // the SimpleTag is valid if ParseSimpleTags returns `true`
311
312
0
            if (vars.obj->ParseSimpleTags( &st, &simple, vars.target_type ))
313
0
              vars.out.sub_tags.push_back( st );
314
0
        }
315
28
    };
316
28
    SimpleTagHandler::Dispatcher().iterate( tag->begin(), tag->end(), &payload );
317
318
28
    if( pout_simple->tag_name.empty() )
319
0
    {
320
0
        msg_Warn( &sys.demuxer, "Invalid MKV SimpleTag found.");
321
0
        return false;
322
0
    }
323
28
    if( !sys.meta )
324
7
        sys.meta = vlc_meta_New();
325
633
    for( int i = 0; metadata_map[i].key; i++ )
326
614
    {
327
614
        if( pout_simple->tag_name == metadata_map[i].key &&
328
614
            (metadata_map[i].target_type == 0 || target_type == metadata_map[i].target_type ) )
329
9
        {
330
9
            vlc_meta_Set( sys.meta, metadata_map[i].type, pout_simple->value.c_str () );
331
9
            msg_Dbg( &sys.demuxer, "|   |   + Meta %s: %s", pout_simple->tag_name.c_str (), pout_simple->value.c_str ());
332
9
            goto done;
333
9
        }
334
614
    }
335
19
    msg_Dbg( &sys.demuxer, "|   |   + Meta %s: %s", pout_simple->tag_name.c_str (), pout_simple->value.c_str ());
336
19
    vlc_meta_SetExtra( sys.meta, pout_simple->tag_name.c_str (), pout_simple->value.c_str ());
337
28
done:
338
28
    return true;
339
19
}
340
341
void matroska_segment_c::LoadTags( KaxTags *tags_ )
342
7
{
343
7
    if ( !ReadMaster( *tags_ ) )
344
0
        return;
345
346
7
    struct TagsHandlerPayload
347
7
    {
348
7
        matroska_segment_c * const obj;
349
7
        EbmlParser         * const ep;
350
7
        demux_sys_t        & sys;
351
7
        int                target_type;
352
7
    } payload = { this, &ep, sys, 50 };
353
7
    MKV_SWITCH_CREATE( EbmlTypeDispatcher, KaxTagsHandler, TagsHandlerPayload )
354
7
    {
355
7
        MKV_SWITCH_INIT();
356
7
        E_CASE( KaxTag, entry )
357
22
        {
358
22
            msg_Dbg( &vars.sys.demuxer, "+ Tag" );
359
22
            Tag tag;
360
22
            struct TagHandlerPayload
361
22
            {
362
22
                matroska_segment_c * const obj;
363
22
                EbmlParser         * const ep;
364
22
                demux_sys_t        & sys;
365
22
                Tag                & tag;
366
22
                int                target_type;
367
22
            } payload = { vars.obj, vars.ep, vars.sys, tag, 50 };
368
22
            MKV_SWITCH_CREATE( EbmlTypeDispatcher, TagHandler, TagHandlerPayload )
369
22
            {
370
22
                MKV_SWITCH_INIT();
371
22
                E_CASE( KaxTagTargets, targets )
372
22
                {
373
22
                    msg_Dbg( &vars.sys.demuxer, "|   + Targets" );
374
375
22
                    MKV_SWITCH_CREATE( EbmlTypeDispatcher, TargetsHandler, TagHandlerPayload )
376
22
                    {
377
22
                        MKV_SWITCH_INIT();
378
22
                        E_CASE( KaxTagTargetTypeValue, entry )
379
22
                        {
380
0
                            vars.target_type = static_cast<uint32_t>( entry );
381
0
                            msg_Dbg( &vars.sys.demuxer, "|   |   + TargetTypeValue: %u", vars.target_type);
382
0
                        }
383
22
                        E_CASE( KaxTagTrackUID, entry )
384
22
                        {
385
15
                            vars.tag.i_tag_type = TRACK_UID;
386
15
                            vars.tag.i_uid = static_cast<uint64_t>( entry );
387
15
                            msg_Dbg( &vars.sys.demuxer, "|   |   + TrackUID: %" PRIu64, vars.tag.i_uid);
388
15
                        }
389
22
                        E_CASE( KaxTagEditionUID, entry )
390
22
                        {
391
0
                            vars.tag.i_tag_type = EDITION_UID;
392
0
                            vars.tag.i_uid = static_cast<uint64_t>( entry );
393
0
                            msg_Dbg( &vars.sys.demuxer, "|   |   + EditionUID: %" PRIu64, vars.tag.i_uid);
394
0
                        }
395
22
                        E_CASE( KaxTagChapterUID, entry )
396
22
                        {
397
0
                            vars.tag.i_tag_type = CHAPTER_UID;
398
0
                            vars.tag.i_uid = static_cast<uint64_t>( entry );
399
0
                            msg_Dbg( &vars.sys.demuxer, "|   |   + ChapterUID: %" PRIu64, vars.tag.i_uid);
400
0
                        }
401
22
                        E_CASE( KaxTagAttachmentUID, entry )
402
22
                        {
403
0
                            vars.tag.i_tag_type = ATTACHMENT_UID;
404
0
                            vars.tag.i_uid = static_cast<uint64_t>( entry );
405
0
                            msg_Dbg( &vars.sys.demuxer, "|   |   + AttachmentUID: %" PRIu64, vars.tag.i_uid);
406
0
                        }
407
22
                        E_CASE( KaxTagTargetType, entry )
408
22
                        {
409
0
                            msg_Dbg( &vars.sys.demuxer, "|   |   + TargetType: %s", entry.GetValue().c_str());
410
0
                        }
411
22
                        E_CASE_DEFAULT( el )
412
22
                        {
413
0
                            msg_Dbg( &vars.sys.demuxer, "|   |   + Unknown (%s)", EBML_NAME(&el) );
414
0
                        }
415
22
                    };
416
417
22
                    TargetsHandler::Dispatcher().iterate( targets.begin(), targets.end(), &vars );
418
22
                }
419
22
                E_CASE( KaxTagSimple, entry )
420
28
                {
421
28
                    SimpleTag simple;
422
423
28
                    if (vars.obj->ParseSimpleTags( &simple, &entry, vars.target_type ))
424
28
                        vars.tag.simple_tags.push_back( simple );
425
28
                }
426
22
                E_CASE_DEFAULT( el )
427
22
                {
428
0
                    msg_Dbg( &vars.sys.demuxer, "|   |   + Unknown (%s)", EBML_NAME(&el) );
429
0
                }
430
22
            };
431
432
22
            TagHandler::Dispatcher().iterate( entry.begin(), entry.end(), &payload );
433
22
            vars.obj->tags.push_back(tag);
434
22
        }
435
7
        E_CASE_DEFAULT( el )
436
7
        {
437
2
            msg_Dbg( &vars.sys.demuxer, "|   + LoadTag Unknown (%s)", EBML_NAME(&el) );
438
2
        }
439
7
    };
440
441
7
    KaxTagsHandler::Dispatcher().iterate( tags_->begin(), tags_->end(), &payload );
442
7
    msg_Dbg( &sys.demuxer, "loading tags done." );
443
7
}
444
445
/*****************************************************************************
446
 * InformationCreate:
447
 *****************************************************************************/
448
void matroska_segment_c::InformationCreate( )
449
17
{
450
17
    if( !sys.meta )
451
10
        sys.meta = vlc_meta_New();
452
453
17
    if( psz_title )
454
0
    {
455
0
        vlc_meta_SetTitle( sys.meta, psz_title );
456
0
    }
457
17
}
458
459
460
/*****************************************************************************
461
 * Misc
462
 *****************************************************************************/
463
464
bool matroska_segment_c::PreloadClusters(uint64_t i_cluster_pos)
465
0
{
466
0
    struct ClusterHandlerPayload
467
0
    {
468
0
        matroska_segment_c * const obj;
469
0
        bool stop_parsing;
470
471
0
    } payload = { this, false };
472
473
0
    MKV_SWITCH_CREATE(EbmlTypeDispatcher, ClusterHandler, ClusterHandlerPayload )
474
0
    {
475
0
        MKV_SWITCH_INIT();
476
477
0
        E_CASE( KaxCluster, kcluster )
478
0
        {
479
0
            vars.obj->ParseCluster( &kcluster, false );
480
0
        }
481
482
0
        E_CASE_DEFAULT( el )
483
0
        {
484
0
            VLC_UNUSED( el );
485
0
            vars.stop_parsing = true;
486
0
        }
487
0
    };
488
489
0
    {
490
0
        es.I_O().setFilePointer( i_cluster_pos );
491
492
0
        while (payload.stop_parsing == false)
493
0
        {
494
0
            EbmlParser parser ( &es, segment, &sys.demuxer );
495
0
            EbmlElement* el = parser.Get();
496
497
0
            if( el == NULL )
498
0
                break;
499
500
0
            ClusterHandler::Dispatcher().send( el, &payload );
501
0
        }
502
0
    }
503
504
0
    return true;
505
0
}
506
507
bool matroska_segment_c::PreloadFamily( const matroska_segment_c & of_segment )
508
0
{
509
0
    if ( b_preloaded )
510
0
        return false;
511
512
0
    if ( SameFamily( of_segment ) )
513
0
        return Preload( );
514
515
0
    return false;
516
0
}
517
518
bool matroska_segment_c::CompareSegmentUIDs( const matroska_segment_c * p_item_a, const matroska_segment_c * p_item_b )
519
0
{
520
0
    EbmlBinary *p_tmp;
521
522
0
    if ( p_item_a == NULL || p_item_b == NULL )
523
0
        return false;
524
525
0
    p_tmp = static_cast<EbmlBinary *>( p_item_a->p_segment_uid );
526
0
    if ( !p_tmp )
527
0
        return false;
528
0
    if ( p_item_b->p_prev_segment_uid != NULL
529
0
          && *p_tmp == *p_item_b->p_prev_segment_uid )
530
0
        return true;
531
532
0
    p_tmp = static_cast<EbmlBinary *>( p_item_a->p_next_segment_uid );
533
0
    if ( !p_tmp )
534
0
        return false;
535
536
0
    if ( p_item_b->p_segment_uid != NULL
537
0
          && *p_tmp == *p_item_b->p_segment_uid )
538
0
        return true;
539
540
0
    if ( p_item_b->p_prev_segment_uid != NULL
541
0
          && *p_tmp == *p_item_b->p_prev_segment_uid )
542
0
        return true;
543
544
0
    return false;
545
0
}
546
547
bool matroska_segment_c::SameFamily( const matroska_segment_c & of_segment ) const
548
0
{
549
0
    for (size_t i=0; i<families.size(); i++)
550
0
    {
551
0
        for (size_t j=0; j<of_segment.families.size(); j++)
552
0
        {
553
0
            if ( *(families[i]) == *(of_segment.families[j]) )
554
0
                return true;
555
0
        }
556
0
    }
557
0
    return false;
558
0
}
559
560
bool matroska_segment_c::Preload( )
561
34
{
562
34
    if ( b_preloaded )
563
17
        return false;
564
565
17
    EbmlElement *el = NULL;
566
567
17
    ep.Reset( &sys.demuxer );
568
569
111
    while( ( el = ep.Get() ) != NULL )
570
111
    {
571
111
        if( MKV_IS_ID( el, KaxSeekHead ) )
572
15
        {
573
            /* Multiple allowed */
574
            /* We bail at 10, to prevent possible recursion */
575
15
            msg_Dbg(  &sys.demuxer, "|   + Seek head" );
576
15
            if( i_seekhead_count < 10 )
577
15
            {
578
15
                i_seekhead_position = el->GetElementPosition();
579
15
                ParseSeekHead( static_cast<KaxSeekHead*>( el ) );
580
15
            }
581
15
        }
582
96
        else if( MKV_IS_ID( el, KaxInfo ) )
583
16
        {
584
            /* Multiple allowed, mandatory */
585
16
            msg_Dbg(  &sys.demuxer, "|   + Information" );
586
16
            if( i_info_position < 0 )
587
2
            {
588
2
                ParseInfo( static_cast<KaxInfo*>( el ) );
589
2
                i_info_position = el->GetElementPosition();
590
2
            }
591
16
        }
592
80
        else if( MKV_CHECKED_PTR_DECL ( kt_ptr, KaxTracks, el ) )
593
16
        {
594
            /* Multiple allowed */
595
16
            msg_Dbg(  &sys.demuxer, "|   + Tracks" );
596
16
            if( i_tracks_position < 0 )
597
2
            {
598
2
                ParseTracks( kt_ptr );
599
2
            }
600
16
            if ( tracks.size() == 0 )
601
0
            {
602
0
                msg_Err( &sys.demuxer, "No tracks supported" );
603
0
            }
604
16
            i_tracks_position = el->GetElementPosition();
605
16
        }
606
64
        else if( MKV_CHECKED_PTR_DECL ( cues, KaxCues, el ) )
607
4
        {
608
4
            msg_Dbg(  &sys.demuxer, "|   + Cues" );
609
4
            if( i_cues_position < 0 )
610
1
            {
611
1
                LoadCues( cues );
612
1
                i_cues_position = el->GetElementPosition();
613
1
            }
614
4
        }
615
60
        else if( MKV_CHECKED_PTR_DECL ( cluster_, KaxCluster, el ) )
616
17
        {
617
17
            if( sys.b_seekable &&
618
17
                var_InheritBool( &sys.demuxer, "mkv-preload-clusters" ) )
619
0
            {
620
0
                PreloadClusters        ( cluster_->GetElementPosition() );
621
0
                es.I_O().setFilePointer( cluster_->GetElementPosition() );
622
0
            }
623
17
            msg_Dbg( &sys.demuxer, "|   + Cluster" );
624
625
626
17
            cluster = cluster_;
627
628
            // add first cluster as trusted seekpoint for all tracks
629
17
            for( tracks_map_t::const_iterator it = tracks.begin();
630
52
                 it != tracks.end(); ++it )
631
35
            {
632
35
                _seeker.add_seekpoint( it->first,
633
35
                SegmentSeeker::Seekpoint( cluster->GetElementPosition(), -1,
634
35
                                          SegmentSeeker::Seekpoint::TrustLevel::QUESTIONABLE ) );
635
35
            }
636
637
            /* stop pre-parsing the stream */
638
17
            break;
639
17
        }
640
43
        else if( MKV_CHECKED_PTR_DECL ( ka_ptr, KaxAttachments, el ) )
641
0
        {
642
0
            msg_Dbg( &sys.demuxer, "|   + Attachments" );
643
0
            if( i_attachments_position < 0 )
644
0
            {
645
0
                ParseAttachments( ka_ptr );
646
0
                i_attachments_position = el->GetElementPosition();
647
0
            }
648
0
        }
649
43
        else if( MKV_CHECKED_PTR_DECL ( chapters, KaxChapters, el ) )
650
0
        {
651
0
            msg_Dbg( &sys.demuxer, "|   + Chapters" );
652
0
            if( i_chapters_position < 0 )
653
0
            {
654
0
                ParseChapters( chapters );
655
0
                i_chapters_position = el->GetElementPosition();
656
0
            }
657
0
        }
658
43
        else if( MKV_CHECKED_PTR_DECL ( tags_, KaxTags, el ) )
659
7
        {
660
7
            msg_Dbg( &sys.demuxer, "|   + Tags" );
661
7
            if(tags.empty ())
662
0
            {
663
0
                LoadTags( tags_ );
664
0
            }
665
7
        }
666
36
        else if( MKV_IS_ID ( el, EbmlVoid ) )
667
36
            msg_Dbg( &sys.demuxer, "|   + Void" );
668
1
        else
669
1
            msg_Dbg( &sys.demuxer, "|   + Preload Unknown (%s)", EBML_NAME(el) );
670
111
    }
671
672
17
    ComputeTrackPriority();
673
674
17
    b_preloaded = true;
675
676
17
    if( cluster )
677
17
        EnsureDuration();
678
679
17
    return true;
680
34
}
681
682
/* Here we try to load elements that were found in Seek Heads, but not yet parsed */
683
bool matroska_segment_c::LoadSeekHeadItem( const EbmlCallbacks & ClassInfos, int64_t i_element_position )
684
54
{
685
54
    int64_t     i_sav_position = static_cast<int64_t>( es.I_O().getFilePointer() );
686
54
    EbmlElement *el;
687
688
54
    es.I_O().setFilePointer( i_element_position, seek_beginning );
689
54
    el = es.FindNextID( ClassInfos, 0xFFFFFFFFL);
690
691
54
    if( el == nullptr || el->IsDummy() )
692
16
    {
693
16
        msg_Err( &sys.demuxer, "cannot load some cues/chapters/tags etc. (broken seekhead or file)" );
694
16
        es.I_O().setFilePointer( i_sav_position, seek_beginning );
695
16
        delete el;
696
16
        return false;
697
16
    }
698
699
38
    if( MKV_CHECKED_PTR_DECL ( ksh_ptr, KaxSeekHead, el ) )
700
0
    {
701
        /* Multiple allowed */
702
0
        msg_Dbg( &sys.demuxer, "|   + Seek head" );
703
0
        if( i_seekhead_count < 10 )
704
0
        {
705
0
            if ( i_seekhead_position != i_element_position )
706
0
            {
707
0
                i_seekhead_position = i_element_position;
708
0
                ParseSeekHead( ksh_ptr );
709
0
            }
710
0
        }
711
0
    }
712
38
    else if( MKV_CHECKED_PTR_DECL ( ki_ptr, KaxInfo, el ) ) // FIXME
713
14
    {
714
        /* Multiple allowed, mandatory */
715
14
        msg_Dbg( &sys.demuxer, "|   + Information" );
716
14
        if( i_info_position < 0 )
717
14
        {
718
14
            ParseInfo( ki_ptr );
719
14
            i_info_position = i_element_position;
720
14
        }
721
14
    }
722
24
    else if( MKV_CHECKED_PTR_DECL ( kt_ptr, KaxTracks, el ) ) // FIXME
723
14
    {
724
        /* Multiple allowed */
725
14
        msg_Dbg( &sys.demuxer, "|   + Tracks" );
726
14
        if( i_tracks_position < 0 )
727
14
            ParseTracks( kt_ptr );
728
14
        if ( tracks.size() == 0 )
729
0
        {
730
0
            msg_Err( &sys.demuxer, "No tracks supported" );
731
0
            delete el;
732
0
            es.I_O().setFilePointer( i_sav_position, seek_beginning );
733
0
            return false;
734
0
        }
735
14
        i_tracks_position = i_element_position;
736
14
    }
737
10
    else if( MKV_CHECKED_PTR_DECL ( kc_ptr, KaxCues, el ) )
738
3
    {
739
3
        msg_Dbg( &sys.demuxer, "|   + Cues" );
740
3
        if( i_cues_position < 0 )
741
3
        {
742
3
            LoadCues( kc_ptr );
743
3
            i_cues_position = i_element_position;
744
3
        }
745
3
    }
746
7
    else if( MKV_CHECKED_PTR_DECL ( ka_ptr, KaxAttachments, el ) )
747
0
    {
748
0
        msg_Dbg( &sys.demuxer, "|   + Attachments" );
749
0
        if( i_attachments_position < 0 )
750
0
        {
751
0
            ParseAttachments( ka_ptr );
752
0
            i_attachments_position = i_element_position;
753
0
        }
754
0
    }
755
7
    else if( MKV_CHECKED_PTR_DECL ( chapters, KaxChapters, el ) )
756
0
    {
757
0
        msg_Dbg( &sys.demuxer, "|   + Chapters" );
758
0
        if( i_chapters_position < 0 )
759
0
        {
760
0
            ParseChapters( chapters );
761
0
            i_chapters_position = i_element_position;
762
0
        }
763
0
    }
764
7
    else if( MKV_CHECKED_PTR_DECL ( tags_, KaxTags, el ) )
765
7
    {
766
7
        msg_Dbg( &sys.demuxer, "|   + Tags" );
767
7
        if(tags.empty ())
768
7
        {
769
7
            LoadTags( tags_ );
770
7
        }
771
7
    }
772
0
    else
773
0
    {
774
0
        msg_Dbg( &sys.demuxer, "|   + LoadSeekHeadItem Unknown (%s)", EBML_NAME(el) );
775
0
    }
776
38
    delete el;
777
778
38
    es.I_O().setFilePointer( i_sav_position, seek_beginning );
779
38
    return true;
780
38
}
781
782
bool matroska_segment_c::Seek( demux_t &demuxer, vlc_tick_t i_absolute_mk_date, vlc_tick_t i_mk_time_offset, bool b_accurate )
783
17
{
784
17
    SegmentSeeker::tracks_seekpoint_t seekpoints;
785
786
17
    SegmentSeeker::fptr_t i_seek_position = std::numeric_limits<SegmentSeeker::fptr_t>::max();
787
17
    vlc_tick_t i_mk_seek_time = -1;
788
17
    vlc_tick_t i_mk_date = i_absolute_mk_date - i_mk_time_offset;
789
17
    SegmentSeeker::track_ids_t selected_tracks;
790
17
    SegmentSeeker::track_ids_t priority;
791
792
    // reset information for all tracks //
793
794
52
    for( tracks_map_t::iterator it = tracks.begin(); it != tracks.end(); ++it )
795
35
    {
796
35
        mkv_track_t &track = *it->second;
797
798
35
        track.i_skip_until_fpos = std::numeric_limits<uint64_t>::max();
799
35
        if( track.i_last_dts != VLC_TICK_INVALID )
800
0
            track.b_discontinuity = true;
801
35
        track.i_last_dts        = VLC_TICK_INVALID;
802
803
35
        bool selected;
804
35
        if (track.p_es == NULL)
805
0
            selected = false;
806
35
        else
807
35
            es_out_Control( demuxer.out, ES_OUT_GET_ES_STATE, track.p_es, &selected );
808
35
        if ( selected )
809
35
            selected_tracks.push_back( track.i_number );
810
35
    }
811
812
17
    if ( selected_tracks.empty() )
813
1
    {
814
1
        selected_tracks = priority_tracks;
815
1
        priority = priority_tracks;
816
1
    }
817
16
    else
818
16
    {
819
16
        std::set_intersection(priority_tracks.begin(),priority_tracks.end(),
820
16
                              selected_tracks.begin(),selected_tracks.end(),
821
16
                              std::back_inserter(priority));
822
16
        if (priority.empty()) // no video selected ?
823
0
            priority = selected_tracks;
824
16
    }
825
826
    // find appropriate seekpoints //
827
828
17
    try {
829
17
        seekpoints = _seeker.get_seekpoints( *this, i_mk_date, priority, selected_tracks );
830
17
    }
831
17
    catch( std::exception const& e )
832
17
    {
833
0
        msg_Err( &sys.demuxer, "error during seek: \"%s\", aborting!", e.what() );
834
0
        return false;
835
0
    }
836
837
    // initialize seek information in order to set up playback //
838
839
52
    for( SegmentSeeker::tracks_seekpoint_t::const_iterator it = seekpoints.begin(); it != seekpoints.end(); ++it )
840
35
    {
841
35
        tracks_map_t::iterator trackit = tracks.find( it->first );
842
35
        if ( trackit == tracks.end() )
843
0
            continue; // there were blocks with unknown tracks
844
845
35
        if( i_seek_position > it->second.fpos )
846
19
        {
847
19
            i_seek_position = it->second.fpos;
848
19
            i_mk_seek_time  = it->second.pts;
849
19
        }
850
851
        // blocks that will be not be read until this fpos
852
35
        if ( b_accurate )
853
35
            trackit->second->i_skip_until_fpos = it->second.fpos;
854
0
        else
855
0
            trackit->second->i_skip_until_fpos = std::numeric_limits<uint64_t>::max();
856
35
        if (it->second.pts != -1)
857
12
            trackit->second->i_last_dts        = it->second.pts + i_mk_time_offset;
858
859
35
        msg_Dbg( &sys.demuxer, "seek: preroll{ track: %u, pts: %" PRId64 ", fpos: %" PRIu64 " skip: %" PRIu64 "} ",
860
35
          it->first, it->second.pts, it->second.fpos, trackit->second->i_skip_until_fpos );
861
35
    }
862
863
17
    if ( i_seek_position == std::numeric_limits<SegmentSeeker::fptr_t>::max() )
864
1
        return false;
865
866
    // propagate seek information //
867
868
16
    sys.i_pcr           = VLC_TICK_INVALID;
869
16
    sys.i_pts           = VLC_TICK_0 + i_mk_seek_time + i_mk_time_offset;
870
16
    if (b_accurate)
871
16
        sys.i_start_pts = VLC_TICK_0 + i_absolute_mk_date;
872
0
    else
873
0
        sys.i_start_pts = sys.i_pts;
874
875
    // make the jump //
876
877
16
    _seeker.mkv_jump_to( *this, i_seek_position );
878
879
    // debug diagnostics //
880
881
16
    msg_Dbg( &sys.demuxer, "seek: preroll{ req: %" PRId64 ", start-pts: %" PRId64 ", start-fpos: %" PRIu64 "} ",
882
16
      sys.i_start_pts, sys.i_pts, i_seek_position );
883
884
    // blocks that will be read and decoded but discarded until this pts
885
16
    es_out_Control( sys.demuxer.out, ES_OUT_SET_NEXT_DISPLAY_TIME, sys.i_start_pts );
886
16
    return true;
887
17
}
888
889
890
mkv_track_t * matroska_segment_c::FindTrackByBlock(
891
                                             const KaxBlock *p_block, const KaxSimpleBlock *p_simpleblock )
892
4.87k
{
893
4.87k
    tracks_map_t::iterator track_it;
894
895
4.87k
    if (p_block != NULL)
896
4.30k
        track_it = tracks.find( p_block->TrackNum() );
897
574
    else if( p_simpleblock != NULL)
898
574
        track_it = tracks.find( p_simpleblock->TrackNum() );
899
0
    else
900
0
        track_it = tracks.end();
901
902
4.87k
    if (track_it == tracks.end())
903
39
        return NULL;
904
905
4.84k
    return track_it->second.get();
906
4.87k
}
907
908
void matroska_segment_c::ComputeTrackPriority()
909
17
{
910
17
    bool b_has_default_video = false;
911
17
    bool b_has_default_audio = false;
912
    /* check for default */
913
52
    for( tracks_map_t::const_iterator it = tracks.begin(); it != tracks.end();
914
35
         ++it )
915
35
    {
916
35
        mkv_track_t &track = *it->second;
917
918
35
        bool flag = track.b_enabled && ( track.b_default || track.b_forced );
919
920
35
        switch( track.fmt.i_cat )
921
35
        {
922
16
            case VIDEO_ES: b_has_default_video |= flag; break;
923
11
            case AUDIO_ES: b_has_default_audio |= flag; break;
924
8
            default: break; // ignore
925
35
        }
926
35
    }
927
928
52
    for( tracks_map_t::iterator it = tracks.begin(); it != tracks.end(); ++it )
929
35
    {
930
35
        tracks_map_t::key_type track_id = it->first;
931
35
        mkv_track_t          & track    = *it->second;
932
933
35
        if( unlikely( track.fmt.i_cat == UNKNOWN_ES || track.codec.empty() ) )
934
0
        {
935
0
            msg_Warn( &sys.demuxer, "invalid track[%d]", static_cast<int>( track_id ) );
936
0
            track.p_es = NULL;
937
0
            continue;
938
0
        }
939
35
        else if( unlikely( !b_has_default_video && track.fmt.i_cat == VIDEO_ES ) )
940
3
        {
941
3
            track.b_default = true;
942
3
            b_has_default_video = true;
943
3
        }
944
32
        else if( unlikely( !b_has_default_audio &&  track.fmt.i_cat == AUDIO_ES ) )
945
2
        {
946
2
            track.b_default = true;
947
2
            b_has_default_audio = true;
948
2
        }
949
35
        if( unlikely( !track.b_enabled ) )
950
0
            track.fmt.i_priority = ES_PRIORITY_NOT_SELECTABLE;
951
35
        else if( track.b_forced )
952
0
            track.fmt.i_priority = ES_PRIORITY_SELECTABLE_MIN + 2;
953
35
        else if( track.b_default )
954
27
            track.fmt.i_priority = ES_PRIORITY_SELECTABLE_MIN + 1;
955
8
        else
956
8
            track.fmt.i_priority = ES_PRIORITY_SELECTABLE_MIN;
957
958
        /* Avoid multivideo tracks when unnecessary */
959
35
        if( track.fmt.i_cat == VIDEO_ES )
960
16
            track.fmt.i_priority--;
961
35
    }
962
963
    // find track(s) with highest priority //
964
17
    {
965
17
        int   score = -1;
966
17
        int es_type = -1;
967
968
52
        for( tracks_map_t::const_iterator it = this->tracks.begin(); it != this->tracks.end(); ++it )
969
35
        {
970
35
            int track_score = -1;
971
972
35
            switch( it->second->fmt.i_cat )
973
35
            {
974
16
                case VIDEO_ES: ++track_score;
975
                /* fallthrough */
976
27
                case AUDIO_ES: ++track_score;
977
                /* fallthrough */
978
35
                case   SPU_ES: ++track_score;
979
                /* fallthrough */
980
35
                default:
981
35
                  if( score < track_score )
982
16
                  {
983
16
                      es_type = it->second->fmt.i_cat;
984
16
                      score   = track_score;
985
16
                  }
986
35
            }
987
35
        }
988
989
52
        for( tracks_map_t::const_iterator it = this->tracks.begin(); it != this->tracks.end(); ++it )
990
35
        {
991
35
            if( it->second->fmt.i_cat == es_type )
992
16
                priority_tracks.push_back( it->first );
993
35
        }
994
17
    }
995
17
}
996
997
void matroska_segment_c::EnsureDuration()
998
17
{
999
17
    if ( i_duration > 0 )
1000
14
        return;
1001
1002
3
    i_duration = -1;
1003
1004
3
    if( !sys.b_fastseekable )
1005
0
    {
1006
0
        msg_Warn( &sys.demuxer, "could not look for the segment duration" );
1007
0
        return;
1008
0
    }
1009
1010
3
    uint64_t i_current_position = es.I_O().getFilePointer();
1011
3
    uint64_t i_last_cluster_pos = cluster->GetElementPosition();
1012
1013
    // find the last Cluster from the Cues
1014
1015
3
    if ( b_cues && _seeker._cluster_positions.size() )
1016
0
        i_last_cluster_pos = *_seeker._cluster_positions.rbegin();
1017
3
    else if( !cluster->IsFiniteSize() )
1018
2
    {
1019
2
        if ( i_last_cluster_pos == cluster->GetElementPosition() )
1020
            // make sure our first Cluster has a timestamp
1021
2
            ParseCluster( cluster, false, SCOPE_PARTIAL_DATA );
1022
2
        return;
1023
2
    }
1024
1025
1
    es.I_O().setFilePointer( i_last_cluster_pos, seek_beginning );
1026
1027
1
    EbmlParser eparser ( &es, segment, &sys.demuxer );
1028
1029
    // locate the definitely last cluster in the stream
1030
1031
2
    while( EbmlElement* el = eparser.Get() )
1032
1
    {
1033
1
        if( !el->IsFiniteSize() && el->GetElementPosition() != i_last_cluster_pos )
1034
0
        {
1035
0
            es.I_O().setFilePointer( i_current_position, seek_beginning );
1036
0
            return;
1037
0
        }
1038
1039
1
        if( MKV_IS_ID( el, KaxCluster ) )
1040
1
        {
1041
1
            i_last_cluster_pos = el->GetElementPosition();
1042
1
            if ( i_last_cluster_pos == cluster->GetElementPosition() )
1043
                // make sure our first Cluster has a timestamp
1044
1
                ParseCluster( cluster, false, SCOPE_PARTIAL_DATA );
1045
1
        }
1046
1
    }
1047
1048
    // find the last timecode in the Cluster
1049
1050
1
    eparser.Reset( &sys.demuxer );
1051
1
    es.I_O().setFilePointer( i_last_cluster_pos, seek_beginning );
1052
1053
1
    EbmlElement* el = eparser.Get();
1054
1
    MKV_CHECKED_PTR_DECL( p_last_cluster, KaxCluster, el );
1055
1056
1
    if( p_last_cluster &&
1057
1
        ParseCluster( p_last_cluster, false, SCOPE_PARTIAL_DATA ) )
1058
1
    {
1059
        // use the last block + duration
1060
1
        uint64_t i_last_timecode = p_last_cluster->GlobalTimestamp();
1061
1
        for (auto l : *p_last_cluster)
1062
42
        {
1063
42
            if( MKV_CHECKED_PTR_DECL ( simpleblock, KaxSimpleBlock, l ) )
1064
34
            {
1065
34
                simpleblock->SetParent( *p_last_cluster );
1066
34
                i_last_timecode = std::max(i_last_timecode, simpleblock->GlobalTimestamp());
1067
34
            }
1068
8
            else if( MKV_CHECKED_PTR_DECL_CONST ( group, KaxBlockGroup, l ) )
1069
7
            {
1070
7
                uint64_t i_group_timecode = 0;
1071
7
                for (auto g : *group)
1072
14
                {
1073
14
                    if( MKV_CHECKED_PTR_DECL ( block, KaxBlock, g ) )
1074
7
                    {
1075
7
                        block->SetParent( *p_last_cluster );
1076
7
                        i_group_timecode += block->GlobalTimestamp();
1077
7
                    }
1078
7
                    else if( MKV_CHECKED_PTR_DECL_CONST ( kbd_ptr, KaxBlockDuration, g ) )
1079
7
                    {
1080
7
                        i_group_timecode += static_cast<uint64_t>( *kbd_ptr );
1081
7
                    }
1082
14
                }
1083
7
                i_last_timecode = std::max(i_last_timecode, i_group_timecode);
1084
7
            }
1085
42
        }
1086
1087
1
        i_duration = VLC_TICK_FROM_NS( i_last_timecode - cluster->GlobalTimestamp() );
1088
1
        msg_Dbg( &sys.demuxer, " extracted Duration=%" PRId64, SEC_FROM_VLC_TICK(i_duration) );
1089
1
    }
1090
1091
    // get back to the reading position we were at before looking for a duration
1092
1
    es.I_O().setFilePointer( i_current_position, seek_beginning );
1093
1
}
1094
1095
bool matroska_segment_c::ESCreate()
1096
17
{
1097
    /* add all es */
1098
17
    msg_Dbg( &sys.demuxer, "found %d es", static_cast<int>( tracks.size() ) );
1099
1100
17
    mkv_track_t *default_tracks[ES_CATEGORY_COUNT] = {};
1101
52
    for( tracks_map_t::iterator it = tracks.begin(); it != tracks.end(); ++it )
1102
35
    {
1103
35
        tracks_map_t::key_type   track_id = it->first;
1104
35
        mkv_track_t            & track    = *it->second;
1105
1106
35
        if( unlikely( track.fmt.i_cat == UNKNOWN_ES || track.codec.empty() ) )
1107
0
        {
1108
0
            msg_Warn( &sys.demuxer, "invalid track[%d]", static_cast<int>( track_id ) );
1109
0
            track.p_es = NULL;
1110
0
            continue;
1111
0
        }
1112
35
        track.fmt.i_id = static_cast<int>( track_id );
1113
1114
35
        if( !track.p_es )
1115
35
        {
1116
35
            track.p_es = es_out_Add( sys.demuxer.out, &track.fmt );
1117
1118
35
            if( track.p_es &&
1119
35
                !sys.ev.AddTrack( track ) )
1120
16
            {
1121
16
                msg_Warn( &sys.demuxer, "Could not register events, interactive menus will not work");
1122
16
            }
1123
35
        }
1124
1125
        /* Turn on a subtitles track if it has been flagged as default -
1126
         * but only do this if no subtitles track has already been engaged,
1127
         * either by an earlier 'default track' (??) or by default
1128
         * language choice behaviour.
1129
         */
1130
35
        if( track.b_default || track.b_forced )
1131
27
        {
1132
27
            mkv_track_t *&default_track = default_tracks[track.fmt.i_cat];
1133
27
            if( !default_track || track.b_default )
1134
27
                default_track = &track;
1135
27
        }
1136
35
    }
1137
1138
17
    for( mkv_track_t *track : default_tracks )
1139
85
    {
1140
85
        if( track )
1141
27
            es_out_Control( sys.demuxer.out, ES_OUT_SET_ES_DEFAULT, track->p_es );
1142
85
    }
1143
1144
17
    return true;
1145
17
}
1146
1147
void matroska_segment_c::ESDestroy( )
1148
17
{
1149
17
    sys.ev.AbortThread();
1150
1151
52
    for( tracks_map_t::iterator it = tracks.begin(); it != tracks.end(); ++it )
1152
35
    {
1153
35
        mkv_track_t & track = *it->second;
1154
1155
35
        if( track.p_es != NULL )
1156
35
        {
1157
35
            es_out_Del( sys.demuxer.out, track.p_es );
1158
35
            sys.ev.DelTrack( track );
1159
35
            track.p_es = NULL;
1160
35
        }
1161
35
    }
1162
17
}
1163
1164
int matroska_segment_c::BlockGet( KaxBlock * & pp_block, KaxSimpleBlock * & pp_simpleblock,
1165
                                  KaxBlockAdditions * & pp_additions,
1166
                                  bool *pb_key_picture, bool *pb_discardable_picture,
1167
                                  int64_t *pi_duration )
1168
1.26k
{
1169
1.26k
    pp_simpleblock = NULL;
1170
1.26k
    pp_block = NULL;
1171
1.26k
    pp_additions = NULL;
1172
1173
1.26k
    *pb_key_picture         = true;
1174
1.26k
    *pb_discardable_picture = false;
1175
1.26k
    *pi_duration = 0;
1176
1177
1.26k
    struct BlockPayload {
1178
1.26k
        matroska_segment_c * const obj;
1179
1.26k
        EbmlParser         * const ep;
1180
1.26k
        demux_t            * const p_demuxer;
1181
1.26k
        KaxBlock          *& block;
1182
1.26k
        KaxSimpleBlock    *& simpleblock;
1183
1.26k
        KaxBlockAdditions *& additions;
1184
1185
1.26k
        int64_t            & i_duration;
1186
1.26k
        bool               & b_key_picture;
1187
1.26k
        bool               & b_discardable_picture;
1188
1.26k
        bool                 b_cluster_timecode;
1189
1190
1.26k
    } payload = {
1191
1.26k
        this, &ep, &sys.demuxer, pp_block, pp_simpleblock, pp_additions,
1192
1.26k
        *pi_duration, *pb_key_picture, *pb_discardable_picture, true
1193
1.26k
    };
1194
1195
1.26k
    MKV_SWITCH_CREATE( EbmlTypeDispatcher, BlockGetHandler_l1, BlockPayload )
1196
1.26k
    {
1197
1.26k
        MKV_SWITCH_INIT();
1198
1199
1.26k
        E_CASE( KaxCluster, kcluster )
1200
1.26k
        {
1201
20
            vars.obj->cluster = &kcluster;
1202
20
            vars.b_cluster_timecode = false;
1203
20
            vars.ep->Down ();
1204
20
        }
1205
1.26k
        E_CASE( KaxCues, kcue )
1206
1.26k
        {
1207
0
            VLC_UNUSED( kcue );
1208
0
            msg_Warn( vars.p_demuxer, "find KaxCues FIXME" );
1209
0
        }
1210
1.26k
        E_CASE_DEFAULT(element)
1211
1.26k
        {
1212
476
            msg_Dbg( vars.p_demuxer, "Unknown (%s)", EBML_NAME(&element) );
1213
476
        }
1214
1.26k
    };
1215
1216
1.26k
    MKV_SWITCH_CREATE( EbmlTypeDispatcher, BlockGetHandler_l2, BlockPayload )
1217
1.26k
    {
1218
1.26k
        MKV_SWITCH_INIT();
1219
1220
1.26k
        E_CASE( KaxClusterTimestamp, ktimecode )
1221
1.26k
        {
1222
22
            ktimecode.ReadData( vars.obj->es.I_O(), SCOPE_ALL_DATA );
1223
22
            vars.obj->cluster->InitTimestamp( static_cast<uint64_t>( ktimecode ), vars.obj->i_timescale );
1224
22
            vars.obj->_seeker.add_cluster( vars.obj->cluster );
1225
22
            vars.b_cluster_timecode = true;
1226
22
        }
1227
1.26k
        E_CASE( KaxClusterSilentTracks, ksilent )
1228
1.26k
        {
1229
0
            vars.ep->Down ();
1230
1231
0
            VLC_UNUSED( ksilent );
1232
0
        }
1233
1.26k
        E_CASE( KaxBlockGroup, kbgroup )
1234
1.26k
        {
1235
1.08k
            vars.obj->i_block_pos = kbgroup.GetElementPosition();
1236
1.08k
            vars.ep->Down ();
1237
1.08k
        }
1238
1.26k
        E_CASE( KaxSimpleBlock, ksblock )
1239
1.26k
        {
1240
184
            if( vars.b_cluster_timecode == false )
1241
0
            {
1242
0
                msg_Warn( vars.p_demuxer, "ignoring SimpleBlock prior to mandatory Timecode" );
1243
0
                return;
1244
0
            }
1245
1246
184
            vars.simpleblock = &ksblock;
1247
184
            vars.simpleblock->ReadData( vars.obj->es.I_O() );
1248
184
            vars.simpleblock->SetParent( *vars.obj->cluster );
1249
1250
184
            if( ksblock.IsKeyframe() )
1251
65
            {
1252
65
                bool const b_valid_track = vars.obj->FindTrackByBlock( NULL, &ksblock ) != NULL;
1253
65
                if (b_valid_track)
1254
52
                    vars.obj->_seeker.add_seekpoint( ksblock.TrackNum(),
1255
52
                        SegmentSeeker::Seekpoint( ksblock.GetElementPosition(), VLC_TICK_FROM_NS(ksblock.GlobalTimestamp()) ) );
1256
65
            }
1257
184
        }
1258
1.26k
    };
1259
1260
1.26k
    MKV_SWITCH_CREATE( EbmlTypeDispatcher, BlockGetHandler_l3, BlockPayload )
1261
1.26k
    {
1262
1.26k
        MKV_SWITCH_INIT();
1263
1264
1.26k
        E_CASE( KaxBlock, kblock )
1265
1.26k
        {
1266
1.08k
            vars.block = &kblock;
1267
1.08k
            vars.block->ReadData( vars.obj->es.I_O() );
1268
1.08k
            vars.block->SetParent( *vars.obj->cluster );
1269
1270
1.08k
            const mkv_track_t *p_track = vars.obj->FindTrackByBlock( &kblock, NULL );
1271
1.08k
            if( p_track != NULL && p_track->fmt.i_cat == SPU_ES )
1272
0
            {
1273
0
                vars.obj->_seeker.add_seekpoint( kblock.TrackNum(),
1274
0
                    SegmentSeeker::Seekpoint( kblock.GetElementPosition(), VLC_TICK_FROM_NS(kblock.GlobalTimestamp()) ) );
1275
0
            }
1276
1277
1.08k
            vars.ep->Keep ();
1278
1.08k
        }
1279
1.26k
        E_CASE( KaxBlockAdditions, kadditions )
1280
1.26k
        {
1281
795
            if ( vars.obj->ReadMaster( kadditions ) )
1282
795
            {
1283
795
                vars.additions = &kadditions;
1284
795
                vars.ep->Keep ();
1285
795
            }
1286
795
        }
1287
1.26k
        E_CASE( KaxBlockDuration, kduration )
1288
1.26k
        {
1289
2
            kduration.ReadData( vars.obj->es.I_O() );
1290
2
            vars.i_duration = static_cast<uint64_t>( kduration );
1291
2
        }
1292
1.26k
        E_CASE( KaxReferenceBlock, kreference )
1293
1.26k
        {
1294
206
           kreference.ReadData( vars.obj->es.I_O() );
1295
1296
206
           if( vars.b_key_picture )
1297
206
               vars.b_key_picture = false;
1298
0
           else if( static_cast<int64_t>( kreference ) )
1299
0
               vars.b_discardable_picture = true;
1300
206
        }
1301
1.26k
        E_CASE( KaxClusterSilentTrackNumber, kstrackn )
1302
1.26k
        {
1303
0
            VLC_UNUSED( kstrackn );
1304
0
            VLC_UNUSED( vars );
1305
0
        }
1306
1.26k
#if LIBMATROSKA_VERSION >= 0x010401
1307
1.26k
        E_CASE( KaxDiscardPadding, kdiscardp )
1308
1.26k
        {
1309
0
            kdiscardp.ReadData( vars.obj->es.I_O() );
1310
0
            int64_t i_duration = static_cast<int64_t>( kdiscardp );
1311
1312
0
            if( vars.i_duration < i_duration )
1313
0
                vars.i_duration = 0;
1314
0
            else
1315
0
                vars.i_duration -= i_duration;
1316
0
        }
1317
1.26k
#endif
1318
1.26k
        E_CASE_DEFAULT( element )
1319
1.26k
        {
1320
6
            VLC_UNUSED(element);
1321
1322
6
            msg_Warn( vars.p_demuxer, "unknown element at { fpos: %" PRId64 ", '%s' }",
1323
6
              element.GetElementPosition(), EBML_NAME( &element ) );
1324
6
        }
1325
1.26k
    };
1326
1327
1.26k
    static EbmlTypeDispatcher const * const dispatchers[] = {
1328
1.26k
        &BlockGetHandler_l1::Dispatcher(),
1329
1.26k
        &BlockGetHandler_l2::Dispatcher(),
1330
1.26k
        &BlockGetHandler_l3::Dispatcher()
1331
1.26k
    };
1332
1333
1.26k
    for( ;; )
1334
6.33k
    {
1335
6.33k
        EbmlElement *el = NULL;
1336
6.33k
        int         i_level;
1337
1338
6.33k
        if( pp_simpleblock != NULL || ((el = ep.Get()) == NULL && pp_block != NULL) )
1339
1.26k
        {
1340
            /* Check blocks validity to protect against broken files */
1341
1.26k
            const mkv_track_t *p_track = FindTrackByBlock( pp_block , pp_simpleblock );
1342
1.26k
            if( p_track == NULL )
1343
22
            {
1344
22
                ep.Unkeep();
1345
22
                pp_simpleblock = NULL;
1346
22
                pp_block = NULL;
1347
22
                continue;
1348
22
            }
1349
1.24k
            if( pp_simpleblock != NULL )
1350
166
            {
1351
166
                *pb_key_picture         = pp_simpleblock->IsKeyframe();
1352
166
                *pb_discardable_picture = pp_simpleblock->IsDiscardable();
1353
166
            }
1354
            /* We have block group let's check if the picture is a keyframe */
1355
1.07k
            else if( *pb_key_picture )
1356
871
            {
1357
871
                if( p_track->fmt.i_codec == VLC_CODEC_THEORA )
1358
8
                {
1359
8
                    DataBuffer *    p_data = &pp_block->GetBuffer(0);
1360
8
                    const uint8_t * p_buff = p_data->Buffer();
1361
                    /* if the second bit of a Theora frame is 1
1362
                       it's not a keyframe */
1363
8
                    if( p_data->Size() && p_buff )
1364
8
                    {
1365
8
                        if( p_buff[0] & 0x40 )
1366
0
                            *pb_key_picture = false;
1367
8
                    }
1368
0
                    else
1369
0
                        *pb_key_picture = false;
1370
8
                }
1371
871
            }
1372
1373
1.24k
            return VLC_SUCCESS;
1374
1.26k
        }
1375
1376
5.06k
        i_level = ep.GetLevel();
1377
1378
5.06k
        if( el == NULL )
1379
1.14k
        {
1380
1.14k
            if( i_level > 1 )
1381
1.12k
            {
1382
1.12k
                ep.Up();
1383
1.12k
                continue;
1384
1.12k
            }
1385
25
            msg_Warn( &sys.demuxer, "EOF" );
1386
25
            return VLC_EGENERIC;
1387
1.14k
        }
1388
1389
        /* Verify that we are still inside our cluster
1390
         * It can happens with broken files and when seeking
1391
         * without index */
1392
3.91k
        if( i_level > 1 )
1393
3.42k
        {
1394
3.42k
            if( cluster && !ep.IsTopPresent( cluster ) )
1395
0
            {
1396
0
                msg_Warn( &sys.demuxer, "Unexpected escape from current cluster" );
1397
0
                cluster = NULL;
1398
0
            }
1399
3.42k
            if( !cluster )
1400
0
                continue;
1401
3.42k
        }
1402
1403
        /* do parsing */
1404
1405
3.91k
        try {
1406
3.91k
            switch( i_level )
1407
3.91k
            {
1408
1.33k
                case 2:
1409
                /* fallthrough */
1410
3.42k
                case 3:
1411
3.42k
                    if( unlikely( !el->ValidateSize() || ( el->IsFiniteSize() && el->GetSize() >= SIZE_MAX ) ) )
1412
0
                    {
1413
0
                        msg_Err( &sys.demuxer, "Error while reading %s... upping level", EBML_NAME(el));
1414
0
                        ep.Up();
1415
1416
0
                        if ( i_level == 2 )
1417
0
                            break;
1418
1419
0
                        ep.Unkeep();
1420
0
                        pp_simpleblock = NULL;
1421
0
                        pp_block = NULL;
1422
1423
0
                        break;
1424
0
                    }
1425
                    /* fallthrough */
1426
3.91k
                case 1:
1427
3.91k
                    {
1428
3.91k
                        EbmlTypeDispatcher const * dispatcher = dispatchers[i_level - 1];
1429
3.91k
                        dispatcher->send( el, &payload );
1430
3.91k
                    }
1431
3.91k
                    break;
1432
1433
0
                default:
1434
0
                    msg_Err( &sys.demuxer, "invalid level = %d", i_level );
1435
0
                    return VLC_EGENERIC;
1436
3.91k
            }
1437
3.91k
        }
1438
3.91k
        catch (int ret_code)
1439
3.91k
        {
1440
0
            return ret_code;
1441
0
        }
1442
3.91k
        catch (...)
1443
3.91k
        {
1444
0
            msg_Err( &sys.demuxer, "Error while reading %s... upping level", EBML_NAME(el));
1445
0
            ep.Up();
1446
0
            ep.Unkeep();
1447
0
            pp_simpleblock = NULL;
1448
0
            pp_block = NULL;
1449
0
        }
1450
3.91k
    }
1451
1.26k
}
1452
1453
} // namespace